Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Invertir lista circular

Estas en el tema de Invertir lista circular en el foro de C/C++ en Foros del Web. El problema es: Tengo una lista (clave) que apunta a una lista circular (valores), concretamente apunta a su último valor, éste al primero, éste al ...
  #1 (permalink)  
Antiguo 02/09/2008, 10:56
 
Fecha de Ingreso: agosto-2008
Mensajes: 161
Antigüedad: 15 años, 8 meses
Puntos: 0
Invertir lista circular

El problema es:
Tengo una lista (clave) que apunta a una lista circular (valores), concretamente apunta a su último valor, éste al primero, éste al siguiente,(hasta llegar al último de nuevo).
En realidad hay muchas claves y éstas tienen valores. Ej:
clave(1)->1.01
clave(2)->2.02->2.01->2.02
clave(3)->3.03->3.02->3.01.->3.03

He hecho éste código pero está mal...

void ordenaValores(Tabla *tabla, funcionCompara fvalores){
NodoClave *claveAux;
NodoValor *valorAux;

claveAux=tabla->primero;
valorAux = claveAux->ultimo->siguiente;
while(claveAux != NULL){
while(claveAux->ultimo!= valorAux){
if(fvalores(valorAux, valorAux->siguiente)>0){
claveAux->ultimo=valorAux->siguien...
}
valorAux=valorAux->siguiente;
}
claveAux = claveAux->siguiente;
}

}

Cómo se haría el código en C para invertir los valores de menor a mayor?

Última edición por una_xikilla; 02/09/2008 a las 11:03
  #2 (permalink)  
Antiguo 02/09/2008, 17:37
 
Fecha de Ingreso: mayo-2006
Ubicación: Venezuela
Mensajes: 33
Antigüedad: 18 años
Puntos: 0
Respuesta: Invertir lista circular

Aja pero que quieres hacer, pq veo q dentro de cada nodo de la lista tienes otra lista
  #3 (permalink)  
Antiguo 02/09/2008, 18:11
 
Fecha de Ingreso: junio-2008
Mensajes: 63
Antigüedad: 15 años, 10 meses
Puntos: 2
Respuesta: Invertir lista circular

Para ordenar listas enlazadas puedes revisar este código:
http://www.forosdelweb.com/f96/caden...3/#post2541093

Claro que tendrás que modificar un poco la función de ordenación para que se detenga correctamente al llegar al último eslabón de la lista, porque si la usas como está con una lista circular se quedará en un bucle infinito.
  #4 (permalink)  
Antiguo 03/09/2008, 10:16
 
Fecha de Ingreso: agosto-2008
Mensajes: 161
Antigüedad: 15 años, 8 meses
Puntos: 0
Respuesta: Invertir lista circular

Hola de nuevo.

Voy a intentar explicarme mejor:

Tengo una lista enlazada con claves (1->2->3->4->...->NULL)

Cada clave tiene valores pero se apunta al último valor y éste al primero... y finalmente vuelve al último (lista circular).

Ej:
clave: 3
valor: 3.010000
valor: 3.020000
valor: 3.030000
valor: 3.000100
valor: 3.000200
valor: 3.000300

En este caso la clave 3 apunta al valor 3.000300->3.010000->3.020000->...->3.000300

Lo que busco es ordenarlo de menor a mayor, es decir:
clave: 3
valor: 3.000100
valor: 3.000200
valor: 3.000300
valor: 3.010000
valor: 3.020000
valor: 3.030000
Quedando que la clave 3 apunte al valor 3.030000->3.000100->3.000200->...->3.030000

He hecho esto pero está mal:
Código:
void ordenaValores(Tabla *tabla, funcionCompara fvalores){
	NodoClave *claveAux;
	NodoValor *valorAux, *valorAuxSig;
	int fin;
	

	for(claveAux = tabla->primero ; claveAux->siguiente != NULL ; claveAux = claveAux->siguiente){
		do {
			fin=0;
			valorAux=claveAux->ultimo;
			valorAuxSig=valorAux->siguiente;
			for (valorAux; valorAux!=valorAuxSig; valorAux=valorAux->sig) {
				if (fvalores (valorAux->valor, valorAuxSig->valor)<0) {
					fin=valorAux->valor; // Uso fin como variable temporal
					valorAux->valor=valorAuxSig->valor;
					valorAuxSig->valor=fin;
					fin=1;
				}
			}
		} while(fin==1);
	
	}
}
Ayuda por favor!!!!
Me estoy volviendo loca!!!
  #5 (permalink)  
Antiguo 03/09/2008, 19:00
 
Fecha de Ingreso: junio-2008
Mensajes: 63
Antigüedad: 15 años, 10 meses
Puntos: 2
Respuesta: Invertir lista circular

Creo que hay unos problemas, al invertir los valores y en el for, prueba esto a ver si te sirve:

Código:
do {
	fin=0;
	valorAux=claveAux; // valorAux debe ser el primer elemento en la lista
	/* Ahora se recorre la lista ordenándola, hasta el último eslabón de la lista,
	en este caso el último eslabón es claveAux->ultimo. */
	for (valorAux; valorAux!=claveAux->ultimo; valorAux=valorAux->sig) {
		if (fvalores (valorAux->valor, valorAux->siguiente->valor)<0) {
			fin=valorAux->valor; // Uso fin como variable temporal
			valorAux->valor=valorAux->siguiente->valor;
			valorAux->siguiente->valor=fin;
			fin=1;
		}
	}
} while(fin==1);

Última edición por yackcae; 03/09/2008 a las 19:05
  #6 (permalink)  
Antiguo 04/09/2008, 05:26
 
Fecha de Ingreso: agosto-2008
Mensajes: 161
Antigüedad: 15 años, 8 meses
Puntos: 0
Respuesta: Invertir lista circular

Códigos:

Código:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "tabla.c"

typedef int Clave;
typedef double Valor;

int comparaClaves( void *c1, void *c2 ) {
  return *(int *)c1 - *(int *)c2;
}

void imprimeClave( void *p ) {
  printf( "clave: %d\n", *(int *)p );
}

void imprimeValor( void *p ) {
	printf("\n%p ", p);
  printf( "  valor: %f\n", *(double *)p );
}

int main( ) {
  Tabla tabla;
  Clave clave;
  Valor valor;
  int i, j;

  inicializa( &tabla, sizeof( Clave ), sizeof( Valor ), comparaClaves );

  for( i = 1; i <= 5; i++ ) {
    clave = i;
    for( j = 1; j <= i; j++ ) {
      valor = i + j / 100.0;
      if( !inserta( &tabla, &clave, &valor ) ) {
        printf( "No se pudo insertar\n" );
      }
    }
  }

  for( i = 9; i >= 1; i-- ) {
    clave = i;
    for( j = 1; j <= i; j++ ) {
      valor = i + j / 10000.0;
      if( !inserta( &tabla, &clave, &valor ) ) {
        printf( "No se pudo insertar\n" );
      }
    }
  }

  printf( "claves: %d, valores: %d\n", (int)numClaves( &tabla ), (int)numValores( &tabla ) );
  printf( "\nRecorrido:\n" ); 

  ordenaValores(&tabla, comparaClaves);
  recorrido( &tabla, imprimeClave, imprimeValor );

  finaliza( &tabla );

  return 0;
}
La otra:

Código:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

typedef void (*funcionProcesa)(void *);

/* Compara dos valores. El resultado será menor, igual o mayor que 0 
 * si el primer elemento es menor, igual o mayor que el segundo */
typedef int (*funcionCompara)(void *,void *);

/*--------------ESTRUCTURAS---------------------*/

/* Nodos de la lista de valores asociados a un NodoClave, será enlazada y
 * circular. El siguiente del último será el primero. */
typedef struct NodoValor{
  void             *valor;  
  struct NodoValor *siguiente; 
} NodoValor;

/* Nodos de la Lista de claves. Será una lista doblemente enlazada ordenada 
 * por el valor de la clave */
typedef struct NodoClave {
  void             *clave;  
  NodoValor        *ultimo;     /* ultimo NodoValor con esta clave */ 
  struct NodoClave *anterior;   /* anterior NodoClave */ 
  struct NodoClave *siguiente;  /* siguiente NodoClave */ 
} NodoClave;

typedef struct {
  size_t         tamClave;       /* tamaño de la clave */  
  size_t         tamValor;       /* tamaño de los valores */  
  size_t         numClaves;      /* numero de claves */  
  size_t         numValores;     /* numero de valores */  
  NodoClave      *primero;       /* primer nodo clave */  
  NodoClave      *ultimo;        /* último nodo clave */  
  funcionCompara comparaClaves;  /* función para comparar las claves */
} Tabla;

/* Posiciones de la Tabla */
typedef struct {
  NodoValor *valor;
  NodoClave *clave;
  Tabla     *tabla;
} Posicion;

/* Creacion. Inicializamos la tabla. Se pasa como parametro el tamaño de cada clave, 
 * el tamaño de los valores y una funcion para comparar claves */
void inicializa(Tabla *tabla, size_t tamClave, size_t tamValor, funcionCompara fclaves){
	tabla->tamClave=tamClave;
	tabla->tamValor=tamValor;
	tabla->numClaves=0;
	tabla->numValores= 0;
	tabla->primero=NULL;
	tabla->ultimo=NULL;
	tabla->comparaClaves=fclaves;

	return;
}

bool inserta(Tabla *tabla, void *clave, void *valor){	
	bool insercionCorrecta=false;
	NodoClave *claveAux, *claveAux2, *nuevaClave;
	NodoValor *nuevoValor, *exValorUltimo;

	claveAux= tabla->primero;

	if (tabla->primero==NULL && tabla->ultimo==NULL){                         /* tabla vacia. */
		nuevaClave= (NodoClave *) malloc (sizeof (NodoClave));
		nuevaClave->clave= (void *) malloc (tabla->tamClave);
		nuevoValor= (NodoValor *)malloc(sizeof(NodoValor));
		nuevoValor->valor= (void *)malloc (tabla->tamValor);

		memcpy(nuevoValor->valor, valor, tabla->tamValor);
		memcpy (nuevaClave->clave, clave, tabla->tamClave);

		nuevaClave->ultimo=nuevoValor;
		nuevoValor->siguiente=nuevoValor;
		nuevaClave->anterior=NULL;
		nuevaClave->siguiente=NULL;

		tabla->primero=nuevaClave;
		tabla->ultimo=nuevaClave;

		tabla->numClaves++;
		tabla->numValores++;

		insercionCorrecta=true;
	}
	else{
		while( claveAux!=NULL && tabla->comparaClaves(claveAux->clave, clave)!=0){
			claveAux=claveAux->siguiente;
		}
		if(claveAux==NULL){      /* La clave no está */
			if (tabla->comparaClaves(clave, tabla->primero->clave)<0 && tabla->primero->anterior==NULL){
				/* la clave es < a la primera */	
				nuevaClave= (NodoClave *) malloc (sizeof (NodoClave));
				nuevaClave->clave= (void *) malloc (tabla->tamClave);
				nuevoValor= (NodoValor *)malloc(sizeof(NodoValor));
				nuevoValor->valor= (void *)malloc (tabla->tamValor);


				memcpy (nuevoValor->valor, valor, tabla->tamValor);
				memcpy (nuevaClave->clave, clave, tabla->tamClave);
			

				nuevaClave->ultimo=nuevoValor;
				nuevoValor->siguiente=nuevoValor;
				nuevaClave->anterior=NULL;
				nuevaClave->siguiente=tabla->primero;
				tabla->primero->anterior=nuevaClave;
				tabla->primero= nuevaClave;

				tabla->numClaves++;
				tabla->numValores++;

				insercionCorrecta=true;
	
				}
			else{
				if (tabla->comparaClaves(clave, tabla->ultimo->clave)>0 && tabla->ultimo->siguiente==NULL){					/* la clave es > a la ultima */
					nuevaClave= (NodoClave *) malloc (sizeof (NodoClave));
					nuevaClave->clave= (void *) malloc (tabla->tamClave);
					nuevoValor= (NodoValor *)malloc(sizeof(NodoValor));
					nuevoValor->valor= (void *)malloc (tabla->tamValor);
					
					memcpy(nuevoValor->valor, valor, tabla->tamValor);
					memcpy (nuevaClave->clave, clave, tabla->tamClave);
					
					nuevaClave->ultimo= nuevoValor;
					nuevoValor->siguiente=nuevoValor;
					nuevaClave->anterior=tabla->ultimo;
					tabla->ultimo->siguiente=nuevaClave;
					nuevaClave->siguiente=NULL;
					tabla->ultimo= nuevaClave;

					tabla->numClaves++;
					tabla->numValores++;

					insercionCorrecta=true;
				}
				else{
					 /* clave entre la primera y la ultima */
					claveAux2=tabla->primero;
					nuevaClave= (NodoClave *) malloc (sizeof (NodoClave));
					nuevaClave->clave= (void *) malloc (tabla->tamClave);
					nuevoValor= (NodoValor *)malloc(sizeof(NodoValor));
					nuevoValor->valor= (void *)malloc (tabla->tamValor);
						
					memcpy(nuevoValor->valor, valor, tabla->tamValor);
					memcpy (nuevaClave->clave, clave, tabla->tamClave);
					
					while(tabla->comparaClaves(claveAux2->clave, clave)<0){
						claveAux2=claveAux2->siguiente;
					}
					nuevaClave->ultimo= nuevoValor;
					nuevoValor->siguiente=nuevoValor;

					nuevaClave->anterior= claveAux2->anterior;
					nuevaClave->siguiente= claveAux2;
					claveAux2->anterior->siguiente=nuevaClave;
					claveAux2->anterior = nuevaClave;

					tabla->numClaves++;
					tabla->numValores++;

					insercionCorrecta=true;
				}
			}
		}
		else{	/* la clave se encuentra en la tabla */
			exValorUltimo=claveAux->ultimo;
				
			nuevoValor= (NodoValor *)malloc(sizeof(NodoValor));
			nuevoValor->valor= (void *)malloc (tabla->tamValor);
			memcpy(nuevoValor->valor, valor, tabla->tamValor);
			
			nuevoValor->siguiente=exValorUltimo->siguiente;
			exValorUltimo->siguiente=nuevoValor;
			claveAux->ultimo=nuevoValor;
			
			tabla->numValores++;

			insercionCorrecta=true;
		}
	}

	return insercionCorrecta;
}

/* Se ordenan en orden ascendente los valores de las listas dentro de cada clave, no se cambian valores entre listas.  
  * Después de la ordenación cada clave tendrá asociados los mismos valores que tenÃ*a, pero estarán ordenados de menor a mayor*/ 
void ordenaValores(Tabla *tabla, funcionCompara fvalores){
	NodoClave *claveAux;
	NodoValor *valorAux, *valorAuxSig;
	void *elemento;
	int fin;
	

	for(claveAux = tabla->primero ; claveAux->siguiente != NULL ; claveAux = claveAux->siguiente){
		do {
			fin=0;
			valorAuxSig=valorAux->siguiente;
			printf("Prueba");
			for (valorAux=claveAux->ultimo; valorAux!=valorAuxSig; valorAux=valorAux->siguiente) {			
				if (fvalores (valorAux->valor, valorAuxSig->valor)<0) {
					elemento=valorAux->valor; /* Uso fin como variable temporal*/
					valorAux->valor=valorAuxSig->valor;
					valorAuxSig->valor=elemento;
					fin=1;
				}
			}
		} while(fin==1);
	
	}
}

/* Recorrido de la tabla. Se procesan las claves de modo ordenado. Para 
 * cada clave se llama a la funcion procesaClave y a continuacion se procesan
 * sus valores asociados, del primero al ultimo, llamando a la funcion 
 * procesaValor */
void recorrido(Tabla *tabla, funcionProcesa procesaClave, funcionProcesa procesaValor){
	NodoValor *valorAux;
  	NodoClave *claveAux;

	claveAux = tabla->primero; 
  	while(claveAux!=NULL){
		procesaClave(claveAux->clave);
	    	valorAux = claveAux->ultimo->siguiente;
  
    		while(claveAux->ultimo != valorAux){
    			procesaValor(valorAux->valor);
		    	valorAux = valorAux->siguiente;
    		}
	    
		procesaValor(valorAux->valor);
		claveAux = claveAux->siguiente;
	}
	return ;
}

/* Destruccion. Se liberan los recursos asociados a la Tabla. Todos los 
 * NodosClave y NodosValor */
void finaliza(Tabla *tabla){
	NodoClave *claveAux;
	NodoValor *valorAux;
	
	claveAux = tabla->primero;
	while(claveAux != NULL){
		valorAux = claveAux->ultimo->siguiente;
		while(claveAux->ultimo != valorAux){
			free(valorAux->valor);
			valorAux = valorAux->siguiente;
			tabla->numValores--;
			printf("Numero de valores de la tabla: %d\n",tabla->numValores);
		}
		tabla->numValores--;
		free(valorAux->valor);
		free(claveAux->clave);
		free(claveAux);
		tabla->numClaves--;
		printf("Numero de claves de latabla: %d\n",tabla->numClaves);
		claveAux = claveAux->siguiente;
	}
	return ;
}
Creo que he metido todo
Ayuda!!
  #7 (permalink)  
Antiguo 05/09/2008, 00:33
 
Fecha de Ingreso: junio-2008
Mensajes: 63
Antigüedad: 15 años, 10 meses
Puntos: 2
Respuesta: Invertir lista circular

La función de comparación no está comparando correctamente, lo hace tratando los valores como si fueran enteros cuando en realidad son double, debería ser así:

Código:
int comparaClaves( void *c1, void *c2 ) {
	if( *(Valor *)c1 - *(Valor *)c2 < 0 ) return -1;
	else if( *(Valor *)c1 - *(Valor *)c2 > 0 ) return 1;
	return 0;
}
No se puede hacer la comparación de la forma:
Código:
	return *(Valor *)c1 - *(Valor *)c2;
porque si los valores a comparar son 0.2 y 0.1 al restarlos daría 0.1 pero al retornarlo como entero se convierte en 0, con lo que se determina erróneamente que son iguales.

La función de comparación la cambié así:

Código:
void ordenaValores(Tabla *tabla, funcionCompara fvalores){
	NodoClave *claveAux;
	NodoValor *valorAux;
	void *elemento;
	int fin;

	for (claveAux = tabla->primero ; claveAux; claveAux=claveAux->siguiente) {
		do {
			fin=0;
			valorAux=claveAux->ultimo->siguiente;
			for (; valorAux!=claveAux->ultimo; valorAux=valorAux->siguiente) {
				if (fvalores(valorAux->valor, valorAux->siguiente->valor)>0) {
					elemento=valorAux->valor;
					valorAux->valor=valorAux->siguiente->valor;
					valorAux->siguiente->valor=elemento;
					fin=1;
				}
			}
		}
		while (fin==1);
	}
}
para probar a ver si funciona he puesto esto es main:

Código:
	clave=1;
	for( i = 1; i <= 5; i++ ) {
		valor=5-i;
		if( !inserta( &tabla, &clave, &valor ) ) {
			printf( "No se pudo insertar\n" );
		}
	}
y esta ha sido la salida:

Código:
Recorrido:
clave: 1

00391180   valor: 0.000000
clave: 1

00391138   valor: 1.000000
clave: 1

003910F0   valor: 2.000000
clave: 1

003910A8   valor: 3.000000
clave: 1

00391060   valor: 4.000000
Numero de claves de latabla: 4
Numero de claves de latabla: 3
Numero de claves de latabla: 2
Numero de claves de latabla: 1
Numero de claves de latabla: 0

Process returned 0 (0x0)   execution time : 0.015 s
Press any key to continue.
Espero que esto te ayude a solucionar el problema.
  #8 (permalink)  
Antiguo 05/09/2008, 06:15
 
Fecha de Ingreso: agosto-2008
Mensajes: 161
Antigüedad: 15 años, 8 meses
Puntos: 0
Respuesta: Invertir lista circular

¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡ YACKCAE ERES MI HÉROE !!!!!!!!!!!!!!!!!

MUCHÍSIMAS GRACIAS!!!!!!!!!!

Lo he solucionado por fín!!!

He hecho algunos cambios pero la clave me la has dado tú.

Aquí lo dejo por si le interesa a alguien:

int comparaValores( void *c1, void *c2 ) {
if( *(double *)c1 - *(double *)c2 < 0 ) return -1;
else if( *(double *)c1 - *(double *)c2 > 0 ) return 1;
return 0;
}

void ordenaValores(Tabla *tabla, funcionCompara fvalores){
NodoClave *claveAux;
NodoValor *valorAux, *valorAuxSig;
void *elemento;
int fin;


for(claveAux = tabla->primero ; claveAux != NULL ; claveAux = claveAux->siguiente){
do {
fin=0;
for (valorAux=claveAux->ultimo->siguiente; valorAux!=claveAux->ultimo; valorAux=valorAux->siguiente) {
valorAuxSig=valorAux->siguiente;
if (fvalores (valorAux->valor, valorAuxSig->valor)>0) {
elemento=valorAux->valor;
valorAux->valor=valorAuxSig->valor;
valorAuxSig->valor=elemento;
fin=1;
}
}
} while(fin==1);

}
}
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 14:45.