1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
/* 6x01-Listas_ordenadas_al_instante 25/01/2012 Implementa una lista ordenada con las operaciones vistas en clase. Utilízala para almacenar en ella todos los datos que hay en un fichero (por ejemplo, uno de resultados de un sorteo de lotería de Navidad, que tenga números premiados y premio que corresponde, que esté desordenado, y usando como criterio de orden los números), y posteriormente guarda la lista ordenada en otro fichero. */ #include <stdio.h> #include <stdlib.h> #include <time.h> #define NUMEROS 10 struct SORTEO { int numero; // Numero de boleto int cuantia; // Importe del premio }; struct NODO { struct SORTEO elemento; // Información contenida en cada nodo de la lista. struct NODO *puntero; // Puntero al siguiente nodo de la lista. }; void insertarEnListaOrdenada( struct NODO **lista, struct SORTEO *cupon ) { /* Precondición: Se ha de recibir un puntero de tipo struct NODO al primer nodo de la lista. Este podrá valer NULL la primera vez o la dirección de memoria que corresponda. El puntero además es un "doble puntero" ya que es necesario poder modificarlo. También se ha de recibir un puntero a una estructura de tipo SORTEO con la información a insertar en la lista. Poscondición: Se inserta la información contenida en "cupon" en un Nodo nuevo perteneciente a "lista", la inserción se realiza con orden ascendente según el "numero" de la estructura "cupon" */ struct NODO *temp = (struct NODO *)malloc(sizeof(struct NODO)); // Se define un puntero temporal de tipo NODO que apunta a la memoria solicitada al sistema. struct NODO *anterior = NULL; // Se crea otro puntero de tipo NODO, este apuntando a NULL struct NODO *siguiente = *lista; // Y un tercer puntero de tipo NODO que apunta al primer nodo de la lista. // En la primera inserción "lista" no apuntara a nada, por lo que se inserta el primer nodo y se hace que "lista" apunte a él. if( *lista == NULL ) { temp->elemento = *cupon; temp->puntero = NULL; *lista = temp; } // Cuando la lista ya tenga al un elemento... else { // Se han de recorrer todos los nodos para comprobar que el orden es correcto, es decir, con orden ascendente: // De modo que se compara el numero del nodo al cual apunta "siguiente" con el numero del cupón que se quiere insertar. // Si se cumple la condición, se guarda en "anterior" el puntero actual, y en "siguiente" se guarda el puntero del nodo siguiente de la lista // En caso de que termine la lista "siguiente" valdrá NULL y "anterior" valdrá N-1 (el ultimo puntero valido) while( siguiente != NULL && siguiente->elemento.numero < cupon->numero ) { anterior = siguiente; siguiente = siguiente->puntero; }; // Si durante la lectura de la lista se llega al final sin encontrar un numero mayor, entonces se inserta el nuevo nodo al final de la lista. if( siguiente == NULL ) { temp->elemento = *cupon; // Se guarda la estructura de datos (cupón) en la estructura del nuevo Nodo. temp->puntero = NULL; // Como la inserción es al final de la lista el puntero del Nodo no a puntara a ningún otro Nodo. anterior->puntero = temp; // Se modifica el puntero del Nodo anterior para que apunte al nuevo Nodo. } // En cambio, si recorriendo la lista se encuentra un numero mayor, se deberá insertar el nuevo nodo antes. else { // Ahora pueden darse dos casos: // Que el nodo a insertar sea el primero de todos, por lo tanto hay que modificar el puntero de "lista" para que apunte al nuevo Nodo: if( *lista == siguiente ) { temp->elemento = *cupon; temp->puntero = siguiente; *lista = temp; } // O que este entre dos nodos, por lo que se modificara el puntero del anterior Nodo para que apunte al nuevo Nodo: else { temp->elemento = *cupon; temp->puntero = siguiente; anterior->puntero = temp; }; }; }; }; void borrarLista( struct NODO **lista ) { /* Precondición: Se ha de recibir un puntero de tipo struct NODO al primer nodo de la lista. Poscondición: Se borran todos los nodos de esa lista hasta llegar a NULL. */ struct NODO *actual, *siguiente; actual = *lista; while(actual != NULL) { siguiente = actual->puntero; free(actual); actual = siguiente; }; *lista = NULL; }; // Función que genera números aleatorios con sus premios aleatorios respectivos y los guarda en "fichero.dat": void generaDat() { /* Poscondición: La función se encarga de generar estructuras con números aleatorios que son guardados en un fichero secuencial. El número de estructuras a guardar viene dado por la constante NUMEROS. */ FILE *ficheroBin = fopen( "sorteo.dat", "w" ); struct SORTEO cupon; int i; srand((unsigned int)time(NULL)); for( i=0; i < NUMEROS; i++ ) { cupon.numero = rand()%100000; cupon.cuantia = rand()%1000; fwrite( &cupon, sizeof(struct SORTEO), 1, ficheroBin ); }; fclose( ficheroBin ); }; // Funcion que pasa el contenido de "fichero.dat" a "fichero.txt": void mostrarDat() { /* Poscondición: Se pasa todo el contenido del fichero secuencial a un fichero de texto. */ FILE *ficheroBin = fopen( "sorteo.dat", "r" ); FILE *ficheroText; struct SORTEO cupon; if( ficheroBin == NULL ) printf( "Genere rimero el fichero \"sorteo.dat\"\n" ); else { ficheroText = fopen( "sorteo.txt", "w" ); fread( &cupon, sizeof(struct SORTEO), 1, ficheroBin ); while( !feof(ficheroBin) ) { fprintf( ficheroText, "%i\t%i\n", cupon.numero, cupon.cuantia ); fread( &cupon, sizeof(struct SORTEO), 1, ficheroBin ); }; fclose( ficheroBin ); fclose( ficheroText ); }; }; main() { struct NODO *lista = NULL; struct NODO *temp; struct SORTEO cupon; FILE *fichOriginal, *fichOrdenDat, *fichOrdenTxt; char opcion; printf( "Elija una opción:\n" ); printf( "1. Ordenar el fichero \"sorteo.dat\" mediante listas\n" ); printf( "2. Generar \"sorteo.dat\"\n" ); printf( "3. Pasar fichero \"sorteo.dat\" a \"sorteo.txt\"\n" ); do{ scanf( "%c", &opcion ); } while( opcion < '1' || opcion > '3' ); if( opcion == '2' ) generaDat(); else if( opcion == '3' ) mostrarDat(); else if( opcion == '1' ) { fichOriginal = fopen("sorteo.dat", "r"); // Se comprueba que el fichero secuencial con el que se ha de trabajar exista: if( fichOriginal == NULL ) printf( "Necesita el fichero \"sorteo.dat\", genérelo primero\n" ); else { // Se recorre todo el fichero, en cada iteración se lee una estructura y se pasa a la función que la guarda en un nuevo Nodo de la lista. // Se lee la primera estructura del fichero y se guarda en la estructura "temporal" de tipo "SORTEO" fread( &cupon, sizeof(struct SORTEO), 1, fichOriginal ); while( !feof(fichOriginal) ) { insertarEnListaOrdenada( &lista, &cupon ); // Se crea un nuevo nodo para el estruct leido y se inserta en la lista. fread( &cupon, sizeof(struct SORTEO), 1, fichOriginal ); // Se lee la siguiente estructura de datos a guardar en la lista. }; fclose(fichOriginal); // Hasta aquí ya se ha leído todo el fichero y se han introducido sus estructuras en cada Nodo de la lista de forma ordenada, ahora hay que pasarlos al fichero de destino. fichOrdenDat = fopen("sorteoOrdenado.dat", "w"); fichOrdenTxt = fopen("sorteoOrdenado.txt", "w"); temp = lista; while( temp != NULL ) { fwrite( &temp, sizeof(struct SORTEO), 1, fichOrdenDat ); fprintf( fichOrdenTxt, "%i\t%i\n", temp->elemento.numero, temp->elemento.cuantia ); temp = temp->puntero; }; fclose(fichOrdenDat); // Ya se ha finalizado el programa, pero antes de terminar del todo hay que liberar toda la memoria RAM usada: borrarLista( &lista ); }; }; printf( " Operación finalizada.\n" ); }; |