Autor
|
Tema: [C] Lista doble y error en campo anterior, siguiente (Leído 2,584 veces)
|
edr89
Desconectado
Mensajes: 105
|
Hola, la semana pasada pregunté por una lista ligada simple y partiendo de ese código agregué un apuntador al campo anterior para convertirla en una lista doble circular. El problema creo sucede cuando le paso los parametros a la funcion que crea el nodo en la linea 30, los parametros son el nombre del jugador, el apuntador del elemento anterior y el apuntador al siguiente. Lo que me esta costando trabajo es visualizar cuando se crea el primer elemento que apunta a si mismo y los demas apuntan al anterior o posterior pero no a si mismos Pregunta: Que apuntador se debe pasar para el campo siguiente? cuando es una lista simple se pasa la direccion del elemento anterior para asignarle en su campo siguiente el valor del nuevo nodo, pero aqui?? reedito: cometi de nuevo el error de asignacion en: if(i==0), ya edite el código#include <stdio.h> #include <stdlib.h> struct persona { char *nombre; struct persona *next; struct persona *prev; }; typedef struct persona JUGADOR; typedef JUGADOR *J_PTR; J_PTR first = NULL; J_PTR last = NULL; J_PTR add_to_list(char *ch, J_PTR prev_rec,J_PTR next_rec); int main() { int i,num_jugadores; char *nombre; J_PTR j_addr = NULL; printf("Escribe el numero de jugadores: "); scanf("%d",&num_jugadores ); printf("\nAhora cada uno de sus nombres\n\n"); for(i=0;i<num_jugadores;i++) { j_addr = add_to_list(nombre, j_addr, first); /*la funcion devuelve new_rec*/ if(i==0) { first = j_addr; } last = j_addr; last->next = first; printf("Nombre:%s\nprev: %p \nnext: %p\n",nombre ,(void *)j_addr ->prev ,(void *)j_addr ->next ); } } J_PTR add_to_list(char *name, J_PTR prev_rec,J_PTR next_rec) { J_PTR new_rec = NULL; new_rec = (J_PTR ) malloc(sizeof(JUGADOR )); // Crear jugador if(!new_rec) { //Validacion de malloc printf("Error al reservar memoria"); } new_rec->nombre = name; new_rec->next = NULL; new_rec->prev = NULL; if(prev_rec) //Si hay un elemento antes { prev_rec->next = new_rec; new_rec->prev = prev_rec; } new_rec->next = next_rec; return(new_rec); }
|
|
« Última modificación: 10 Octubre 2013, 03:18 am por edr89 »
|
En línea
|
|
|
|
eferion
Desconectado
Mensajes: 1.248
|
Si la lista es circular, el primer elemento que metas tendrá que apuntarse a sí mismo... hasta ahí todo claro.
A la hora de insertar el segundo elemento se dará la particularidad de que, como tiene que seguir siendo una lista circular, el anterior y el posterior del primer elemento será el segundo elemento y viceversa:
A <-> B <-> A
Y ya de ahí en adelante la lista tiene el formato que tú ya conoces:
A <-> B <-> C <-> A
La única situación diferente es insertar el primer elemento, que tienes que hacer que se apunte a sí mismo... en el resto de casos sólo tienes que decidir la posición en la que vas a insertarlo y asignar los punteros anterior y posterior de los elementos que estén delante y detrás ( recuerda que al ser circular no habrá punteros nulos y, por tanto, todos los punteros serán válidos )
|
|
|
En línea
|
|
|
|
edr89
Desconectado
Mensajes: 105
|
recuerda que al ser circular no habrá punteros nulos y, por tanto, todos los punteros serán válidos Si, primero creo una lista doble y uso dos apuntadores auxiliares, uno inicial y otro final, ya que se agregaron todos los elementos cierro la lista con: first->prev = last;
Me di cuenta que no tiene sentido pasar el apuntador inicial como parametro al crear el elemento, modificando el código ahora si imprime las direcciones correctas. J_PTR add_to_list(char *name, J_PTR prev_rec) { J_PTR new_rec = NULL; new_rec = (J_PTR ) malloc(sizeof(JUGADOR )); // Crear jugador if(!new_rec) { //Validacion de malloc printf("Error al reservar memoria"); } new_rec->nombre = name; new_rec->next = NULL; new_rec->prev = NULL; if(prev_rec) //Si hay un elemento antes { prev_rec->next = new_rec; new_rec->prev = prev_rec; } return(new_rec); }
El resultado final es un juego que elimina jugadores de una lista hasta quedar el ultimo. Es posible que el algoritmo no sea el mas eficiente, lo he podido compilar y funciona. #include <stdio.h> #include <stdlib.h> #define PINPONPAPAS 6 struct persona { char *nombre; struct persona *next; struct persona *prev; }; typedef struct persona JUGADOR; typedef JUGADOR *J_PTR; J_PTR first = NULL; J_PTR last = NULL; char *input_nombre(size_t long_max); J_PTR add_to_list(char *ch, J_PTR prev_rec); char input_error_conteo(); int input_error_num_jugadores(); int input_mayor_lista(int jugadores); char input_error_sino(); void pausa(); void pin_pon_papas(); int main() { int i,num_jugadores; int inicio_conteo, pin; //Numero de jugador para empezar el juego y numero de veces que se va a contar respectivamente char direccion_conteo; // Las opciones son D = derecha, I = izquierda char bucle ='X'; //para repetir el programa char *nombre; J_PTR j_addr = NULL; //Apunta a los elementos creados en la funcion add_to_list() J_PTR j_aux = NULL; //Este apuntador se usa cuando se van eliminando los jugadores cada 6 conteos do { pin_pon_papas(); printf("\n\nEnlista a los jugadores y elimina uno a uno para terminar con un ganador\n"); printf("\n\nEscribe el numero de jugadores: "); num_jugadores = input_error_num_jugadores(); while(getchar()!='\n'); //limpiar buffer printf("\nAhora cada uno de sus nombres\n\n"); for(i=0;i<num_jugadores;i++) { nombre = input_nombre(30);//Se crean nombres, el parametro es la longitud maxima de texto j_addr = add_to_list(nombre, j_addr); /*la funcion devuelve new_rec*/ if(i==0) { first = j_addr; } last = j_addr; //se recorre al ultimo jugador tecleado. } first->prev = last;//cierre de last->next = first;//lista circular j_addr = first; //Recorrer apuntador al primer elemento creado para imprimir la lista de jugadores. printf("\nEstos son los participantes:\n\n"); for(i=0;i<num_jugadores;i++) { printf("%2d: %s\n",i +1,j_addr ->nombre ); // printf("Nombre:%s\nDireccion jugador:%p\nprev: %p \nnext: %p\n",nombre,(void *)j_addr,(void *)j_addr->prev,(void *)j_addr->next); j_addr = j_addr->next; } printf("\nEscribe el numero de jugador con el que quieres iniciar el conteo: "); inicio_conteo = input_mayor_lista(num_jugadores); while(getchar()!='\n'); //key buffer j_addr = first; for(i=0;i<inicio_conteo-1;i++) { j_addr = j_addr->next; } printf("\n\nHas elegido a %s !\n\n",j_addr ->nombre ); printf("Quieres iniciar el conteo hacia la derecha o izquierda? (D/I)"); direccion_conteo = input_error_conteo(); //validar dato tecleado puts("\nIniciando conteo...\n"); if(direccion_conteo=='D') { for(pin=0;pin<num_jugadores-1;pin++) { for(i=0;i<PINPONPAPAS;i++) { //Ubicar al jugador a eliminar j_addr = j_addr->next; } pin_pon_papas(); printf(", sale %s\n\n",j_addr ->nombre ); j_aux = j_addr->next; j_aux->prev = j_addr->prev; j_aux = j_addr->prev; j_aux->next = j_addr->next; j_aux = j_addr->prev; j_addr = j_aux; pausa(); } } else { for(pin=0;pin<num_jugadores-1;pin++) { for(i=0;i<PINPONPAPAS;i++) { //Ubicar al jugador a eliminar j_addr = j_addr->prev; } pin_pon_papas(); printf(", sale %s\n\n",j_addr ->nombre ); j_aux = j_addr->next; j_aux->prev = j_addr->prev; j_aux = j_addr->prev; j_aux->next = j_addr->next; j_aux = j_addr->next; j_addr = j_aux; pausa(); } } printf("\nEl ultimo jugador en pie es %s!\n",j_addr ->nombre ); printf("\n\nQuieres jugar de nuevo? ( S/N ): "); bucle = input_error_sino(); first = NULL; last = NULL; j_aux = NULL; j_addr = NULL; i=0; }while(bucle=='S'); return 0; } /*Funcion: J_PTR add_to_list() Proposito: Crear un bloque en memoria para el jugador y asigna los apuntadores a siguiente y previo*/ J_PTR add_to_list(char *name, J_PTR prev_rec) { J_PTR new_rec = NULL; new_rec = (J_PTR ) malloc(sizeof(JUGADOR )); // Crear jugador if(!new_rec) { //Validacion de malloc printf("Error al reservar memoria"); } new_rec->nombre = name; new_rec->next = NULL; new_rec->prev = NULL; if(prev_rec) //Si hay un elemento antes { prev_rec->next = new_rec; new_rec->prev = prev_rec; } //aqui solamente se crea la lista doble, en main()es donde se cierra la lista return(new_rec); } /*Funcion: input_nombre(size_t long_max) Proposito: Funcion para entrada de datos, primero reservo el espacio en memoria de longitud definida en el parametro long max, despues sigue la entrada de datos.*/ char *input_nombre(size_t long_max) { char *nombre =NULL; if ((nombre = malloc(long_max + 1)) != NULL ) { //en caso de que no haya bloques de memoria if (fgets(nombre , long_max , stdin ) == NULL ) { nombre = NULL; } else { size_t i; for (i = 0; nombre[i] != '\0' && nombre[i] != '\n'; i++); if (nombre[i] == '\n') { nombre[i] = '\0'; } else { int ch; while ((ch = getchar()) != EOF && ch != '\n'); } } } return nombre; } /*Funcion: input_error_conteo Proposito: Solo permte dos opciones D = derecha, I = izquierda.*/ char input_error_conteo() { char direccion='\0'; while(direccion!='D'&&direccion!='I') //Error { printf("\nDato no valido, intenta de nuevo: "); direccion = getche(); } return direccion; } /*Funcion: input_error Proposito: Valida que los datos de entrada del usuario sean numeros, evita que se procesen letras o signos.*/ int input_error_num_jugadores() { int respuesta; char si_no; while((scanf("%d",&respuesta ) != 1)||respuesta <2||respuesta >50) //en caso de ñ o datos raros. { if(respuesta==1) { printf("\n\nAl menos debe haber 2 jugadores: "); } else if(respuesta<1) { printf ("\n\nDato no valido intenta de nuevo: "); } else { printf("\n\nEl juego no permite mas de 50 jugadores: "); } } return respuesta; } /*Funcion: input_mayor_lista Proposito: Valida que los datos de entrada del usuario sean numeros, evita que se procesen letras, signos o numeros negativos, se usa cuando se pregunta por el jugador a partir del cual se iniciara el conteo.*/ int input_mayor_lista(int jugadores) { int respuesta; while((scanf("%d",&respuesta ) != 1)||respuesta <=0||respuesta >jugadores ) //en caso de ñ y datos raros. { printf ("\nDato no valido intenta de nuevo: "); } return respuesta; } /*Funcion:input_error_sino Proposito: Valida que la respuesta sea el caracter S o N, se usa en la ultima pregunta para volver a correr el programa */ char input_error_sino() { char respuesta; respuesta = getche(); while(respuesta!='S'&&respuesta!='N') //Error si teclea otra cosa { printf("Opcion invalida, intenta de nuevo: "); respuesta = getche(); }//Fin mensaje error return (respuesta); } void pausa() { int delay; for(delay=0;delay<181111100;delay++); //espacio entre impresiones } void pin_pon_papas() { pausa(); pausa(); pausa(); }
|
|
« Última modificación: 16 Octubre 2013, 09:33 am por Eternal Idol »
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Como recorrer registros asi : "Inicio - Siguiente - Anterior - Final" ???
PHP
|
Lupin
|
5
|
6,017
|
14 Mayo 2011, 22:24 pm
por Lupin
|
|
|
¿Cómo crear un visualizador de imágenes con botones de siguiente y anterior?
.NET (C#, VB.NET, ASP)
|
Juancho25
|
4
|
9,185
|
1 Mayo 2013, 12:31 pm
por ABDERRAMAH
|
|
|
ayuda en un programa que encuentre el día anterior, el dìa y día siguiente,en C
Ejercicios
|
Ale_21
|
1
|
2,807
|
31 Octubre 2014, 17:24 pm
por rir3760
|
|
|
[Ayuda] PHP anterior siguiente imagen
PHP
|
Anonymatrix
|
2
|
2,091
|
6 Mayo 2016, 00:58 am
por Anonymatrix
|
|
|
Ayuda con boton anterior y siguiente en PHP
PHP
|
Maxi.Zamorano
|
0
|
1,655
|
26 Diciembre 2018, 19:04 pm
por Maxi.Zamorano
|
|