Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: GGZ en 5 Mayo 2016, 13:52 pm



Título: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 5 Mayo 2016, 13:52 pm
Las listas enlazadas implementadas con punteros tienen la flexibilidad de poder insertar elementos en cualquier parte de ellas sin mover los elementos anteriores ni posteriores, mientras que los arreglos no cuentan con esta flexibilidad.
Proponga una implementación de similar a listas enlazadas, pero de longitud fija, utilizando arreglos, y que provea esta flexibilidad.


Me maté pensandolo pero no me sale, no tengo alguna idea para empezar, ¿alguien que me pueda encaminar?, por favor.



Y tengo otra duda con un problema de tipos que tengo en mi cabeza al parecer(no tiene nada que ver con el anterior ejercicio):

Código
  1. SList slist_append(SList list, int data)
  2. {
  3.      SList newNode = malloc(sizeof(SNode));
  4.      SList node;
  5.      slist_data(newNode) = data;
  6.      slist_next(newNode) = NULL;
  7.      if (list == slist_nil()) {
  8.         return newNode;
  9.      }
  10.      node = list;
  11.      while (slist_next(node) != slist_nil()) {
  12.            node = slist_next(node);
  13.      }
  14.      /* ahora 'node' apunta al ultimo nodo en la lista */
  15.      slist_next(node) = newNode;
  16.      return list;
  17. }
  18.  

¿Por qué retorna list, no sería node?
Si yo estoy trabajando con node y no con list, a list ni siquiera lo he tocado es porque es algún puntero o algo así?

No lo entiendo

Saludos!


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: AlbertoBSD en 5 Mayo 2016, 15:47 pm
Hay un parte del codigo que dice..

Código
  1. node = list;

Tendriamos que ver la estructura de slist.

Ayer hice una implementacion similar

Un nodo en una lista doblemwnte ligada tiene 2 apuntadores.

Uno apunta an nodo anterior y otro al siguiente nodo.

Y Nodo Lista se podria interpretar que apunta al primer nodo y al ultimo nodo asi la lista completa sigue siendo del tipo nodo.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: MAFUS en 5 Mayo 2016, 16:31 pm
Hace una cosa extraña.

Está pensado para modificar la misma lista que se le pasa, pero en vez de modificar directamente el parámetro list lo que hace es modificarlo y regresar un puntero con el dato modificado. Seguramente el autor pensó en esa solución para dar un valor en caso de que list fuera NULL. Pero hubiera hecho lo mismo con un puntero a puntero y el resultado habría sido más natural.

Supongamos el siguiente trozo de código:
Código
  1. SList mi_lista = NULL;
  2.  
  3. mi_lista = slist_append(mi_lista, 5);

Ahora mi_lista pasa a tener un elemento con un valor en data de 5. Continuamos con la variable mi_lista tal y como la hemos dejado en el siguiente código:
Código
  1. mi_lista = slist_append(mi_lista, 7);
Ahora mi_lista tiene dos elementos, uno que contiene el 5 y otro que contiene el 7. Se puede representar así [5 , 7].

Pero qué pasaría si hubiera:
Código
  1. SList lista_uno = NULL;
  2. SList lista_dos = NULL;
  3.  
  4. lista_uno = slist_append(lista_uno, 5);
  5. lista_dos = slist_append(lista_uno, 7);
¿Era esto lo que esperaba el autor que se hiciera?

Casi mejor hubiera sido definir la función con un puntero a puntero.
Código
  1. void slist_append(SList * list, int data) {
  2.    /* Implementación de la función */
  3. }
  4.  
  5. /* Código y más código */
  6.  
  7. SList mi_lista = NULL;
  8. slist_append(&mi_lista, 5);
  9. slist_append(&mi_lista, 7);

Ahora mi_lista estaría actualizada con [5 , 7] pero no habría posibilidad de darle a otra lista la posibilidad de acceder a los datos de ésta con lo que se previenen errores a la hora de escribir el programa.

Por otra parte esconder un puntero dentro de un typedef no es muy buena práctica, pero cada uno hace lo que quiere.

Por otra parte, sobre la primera pregunta: tal vez un array de punteros. Los elementos apuntados no se mueven de su sitio, lo que cambias son los punteros del array y tienes un array para acceder a ellos.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 5 Mayo 2016, 16:34 pm
Esta es la implementación ahora te leo MAFUS xD

Código
  1. typedef struct _SNode {
  2.        int    data;
  3.        struct _SNode *next;
  4. } SNode;
  5.  
  6. typedef SNode *SList;
  7.  
  8. #define slist_data(l)       (l)->data
  9. #define slist_next(l)       (l)->next
  10. #define slist_nil()         NULL
  11.  


Código
  1. #include <stdlib.h>
  2. #include "SList.h"
  3.  
  4. SList slist_append(SList list, int data)
  5. {
  6.      SList newNode = malloc(sizeof(SNode));
  7.      SList node;
  8.      slist_data(newNode) = data;
  9.      slist_next(newNode) = NULL;
  10.      if (list == slist_nil()) {
  11.         return newNode;
  12.      }
  13.      node = list;
  14.      while (slist_next(node) != slist_nil()) {
  15.            node = slist_next(node);
  16.      }
  17.      /* ahora 'node' apunta al ultimo nodo en la lista */
  18.      slist_next(node) = newNode;
  19.      return list;
  20. }
  21.  
  22. SList slist_prepend(SList list, int data)
  23. {
  24.      SList newNode = malloc(sizeof(SNode));
  25.      slist_next(newNode) = list;
  26.      slist_data(newNode) = data;
  27.      return newNode;
  28. }
  29.  
  30. void  slist_destroy(SList list)
  31. {
  32.      SList nodeToDelete;
  33.  
  34.      while (list != slist_nil()) {
  35.            nodeToDelete = list;
  36.            list = slist_next(list);
  37.            free(nodeToDelete);
  38.      }
  39. }
  40.  
  41. void  slist_foreach(SList list, VisitorFuncInt visit, void *extra_data)
  42. {
  43.      SList node = list;
  44.  
  45.      while (node != slist_nil()) {
  46.            visit(slist_data(node), extra_data);
  47.            node = slist_next(node);
  48.      }
  49. }
  50.  

Tengo un lío de tipos en la cabeza. ¿Por qué regresa un puntero si los dos están declarados de la misma forma AAAHHHH WTFF !! ?


Citar
¿Era esto lo que esperaba el autor que se hiciera?

No te entiendo bien, pero no creo ¿por qué así?
Yo sólo pregunté por qué retorna node jaja tengo más confusión ahora.
 


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: AlbertoBSD en 5 Mayo 2016, 16:42 pm
Por otra parte, sobre la primera pregunta: tal vez un array de punteros. Los elementos apuntados no se mueven de su sitio, lo que cambias son los punteros del array y tienes un array para acceder a ellos.

La solucion de MAFUS es totalmente valida.


Proponga una implementación de similar a listas enlazadas, pero de longitud fija, utilizando arreglos, y que provea esta flexibilidad.


Aun así si lo que quieren es no usar apuntadores, el campo next podría ser una variable entera que sea el index relativo al elemento de la tabla por ejemplo si next  es 4 y quien inserta ahi un nuevo nodo, el nodo se escribe al final de la tabla y entonce el nodo que tenia next = 4 se cambia por final y ahora el nodo final es su valor next tendría 4.

Es casi lo mismo pero es otra solución, aun así utilizando arreglos lo veo poco practico por que no sabes cuantos nodos serán insertados



Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 5 Mayo 2016, 17:04 pm
AlbertoBSD, puedes escribir un troso de código o algún ejemplo así me queda un poco más claro para guiarme no digo que lo hagas es que estoy medio perdido.
Encima el Viernes de la semana que viene rindo, pero llego bien si entiendo esto.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: AlbertoBSD en 5 Mayo 2016, 20:10 pm
Código
  1.  
  2. typedef struct {
  3. int anterior;
  4. int valor;
  5. int siguiente;
  6. }Nodo;
  7.  
  8. int main() {
  9. Nodo lista[100];
  10. }
  11.  

Los nodos podrían insertarse en el primer hueco disponible dentro del arreglo, las variables anterior y siguiente podrian apuntar a la posicion relativa dentro del la lista.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 6 Mayo 2016, 09:15 am
Citar
Está pensado para modificar la misma lista que se le pasa, pero en vez de modificar directamente el parámetro list lo que hace es modificarlo y regresar un puntero con el dato modificado. Seguramente el autor pensó en esa solución para dar un valor en caso de que list fuera NULL. Pero hubiera hecho lo mismo con un puntero a puntero y el resultado habría sido más natural.

¿Cómo que un puntero al dato modificado si los dos tienen el mismo tipo!?

Último ejercicio que me queda sigo intentando pero pregunto por si las dudas después me quedo trabado

Suponga que está implementando una lista doblemente enlazada. Si en lugar de guardar punteros a los nodos previo y siguiente, guarda un xor de ambos punteros: ¿puede recorrer la lista en ambas direcciones ¿Cómo? Defina en C la estructura correspondiente, ¿qué problemas puede encontrar?

Es lo último, denme una mano en esta.

Saludos!


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: MAFUS en 6 Mayo 2016, 10:10 am
La funciones lo que hacen es devolver el inicio de la lista modificada.
Le entregas la lista y la modificación y la función te la devuelve modificada.

Si quieres que sea más específico deberás decirme exactamente que es que no entiendes.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 6 Mayo 2016, 17:53 pm
Código
  1.  
  2. SList slist_append(SList list, int data)
  3. {
  4.      SList newNode = malloc(sizeof(SNode));
  5.      SList node;
  6.      slist_data(newNode) = data;
  7.      slist_next(newNode) = NULL;
  8.      if (list == slist_nil()) {
  9.         return newNode;
  10.      }
  11.      node = list;
  12.      while (slist_next(node) != slist_nil()) {
  13.            node = slist_next(node);
  14.      }
  15.      /* ahora 'node' apunta al ultimo nodo en la lista */
  16.      slist_next(node) = newNode;
  17.      return list;
  18. }
  19.  

Ya sé que el objetivo de la funcón es que devuelva la lista modificada pero no entiendo adónde la modifica, si no toca a list.
A la lista original (list) nunca lo toca, lo único que hace es decir que node = list y de ahí trabaja con node, pisa todos los datos que hay en node (por el node = slist_next(node)), por eso para mí falta algo como slist_next(list)=node;

No logro entender la lógica del código, no sé donde la modifica a lista, para mi esta devolviendo la misma lista que se le pasó sin modificación alguna.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: MAFUS en 6 Mayo 2016, 18:39 pm
La premisa para que funcione la función es que la lista siempre debe estar terminada con NULL. Si está vacía debe estar apuntando a NULL.

La función pondrá el nodo generado con el dato al final de la lista. Siguiendo la primera premisa éste último nodo debe apuntar a NULL en next.

Lo que se hace es:
Se genera un nodo a partir de la información dada por data.

Si la lista está vacía, NULL, pasará a apuntar al nodo nuevo.
Si la lista no está vacía hay que recorrerla hasta encontrar el último elemento (aquel que apunte a NULL), cambiar el valor next para que apunte al nuevo nodo generado y regresar la lista entera, eso es el primer elemento (list).

Lo que ves en
Código
  1. while (slist_next(node) != slist_nil()) {
  2.    node = slist_next(node);
es precisamente ese recorrido. node apunta al principio de la lista (list) y vamos a trabajar sobre node. Mientras el elemento next de node no sea NULL, node apuntará a node->next (en el código esto está encapsulado por node = slist_next(node). Una vez llegado a éste último elemento la orden list_next(node) = newNode; coloca el nuevo nodo al final de la lista.
Como el inicio de la lista no ha sido modificado (list) y hay que regresar un puntero, precisamente al inicio de la lista, devolvemos list.

Otra versión sin estas macros es así:
Código
  1. SList slist_append(SList list, int data) {
  2.    Slist node;
  3.    SList newNode = malloc(sizeof(SNode));
  4.  
  5.    newNode->data = data;
  6.    newNode->next = NULL;
  7.  
  8.    if(list == NULL)
  9.        return newNode;
  10.  
  11.    node = list;
  12.  
  13.    while(node->next != NULL)
  14.        node = node->next;
  15.  
  16.    node->next = newNode;
  17.  
  18.    return list;
  19. }


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 7 Mayo 2016, 03:27 am
Me explicaste todo lo que yo ya sabía, se como trabaja la función se lo que hace, pero no entiendo como la enlaza o sea como relaciona list con node, eso es lo que no entiendo.

O sea como que yo modifico node y también se modifica list si nunca lo relacioné sólo dije node = list (pero acá no estoy cambiando ningún valor de list) y nada más.


ENTIENDO TODO LO QUE HACE LA FUNCIÓN, LO QUE NO ENTIENDO ES PORQUE RETORNA LIST SI NUNCA LO TOCA SI NUNCA LO MODIFICA A LIST, NUNCA DICE "EL SIGUIENTE ELEMENTO DE LIST APUNTA AL NODE"


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: MAFUS en 7 Mayo 2016, 05:08 am
A ver si me se explicar ahora:
node es una variable puntero auxiliar. Su única función es, junto al while, encontrar el último nodo de la lista.
La variable list no se toca, es el inicio de la lista, lo que hay que regresar. Pero la lista sí que se ha modificado, ha crecido en un elemento.

node = list; es porqué la lista es un dato dinámico y no sabemos que extensión tiene pero sabemos que list, al menos, tiene un nodo válido y que ése es el primero; por tanto hay que empezar a buscar el último nodo de la lista por el primero y recorrerla hasta llegar al final.

A ver si me salen los dibujitos esquemáticos:

Código:

XXXXXXXXX <- Esto es nuestra lista

y como toda lista enlazada tiene un puntero apuntando a su cabeza

list
v
XXXXXXXXX



Y <- elemento nuevo que se debe colocar a la lista

como list no se puede tocar, que es lo que hay que regresar nos inventamos node

list
v
XXXXXXXXX      <- esto es node = list
^
node


Y <- por simplicidad lo dejaré perdido por el limbo hasta que lo coloque

ahora node debe encontrar el último elemento

list
v
XXXXXXXXX
 ^
 node

list
v
XXXXXXXXX
  ^
  node

list
v
XXXXXXXXX
   ^
   node

...

list
v
XXXXXXXXX
        ^
        node

Ahora el next de node, que es exactamente lo mismo al next del último elemento enlaza a Y y virtualmente obtenemos lo siguiente

list
v
XXXXXXXXXY

node, ya no me sirve y lo dejo tranquilo. Desaparecerá cuándo desaparezca la función ya que es una variable local.

La lista se queda ya que es algo que hay en el motón y por tanto permanente.

Debo retornar list porqué apunta a la lista modificada.

Ahora me puedes decir: pero si list tiene la misma posición de memoria al principio de la función que al final, no se ha modificado en nada el valor que guarda, no hace falta devolverla.

Y te digo: sí que hace falta porqué también sirve la función para generar la lista desde cero. Si se le pasa list=NULL a la función ocurre lo siguiente:
Código:

list
v
NULL

genero un dato

list
v
NULL

X <- el dato

y enlazo list con el dato

list
v
X


Ahora si no devuelvo list fuera de la función no existiría esta modificación.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 7 Mayo 2016, 16:05 pm
Lo que yo no entiendo es este paso:

Código:
list
v
XXXXXXXXX
        ^
        node

Ahora el next de node, que es exactamente lo mismo al next del último elemento enlaza a Y y virtualmente obtenemos lo siguiente

list
v
XXXXXXXXXY

Ya sé que el next de node es el ÚLTIMO elemento ya sé eso, pero no sé como lo enlaza capaz no entendí bien la definición de las estructuras o sea yo tenía entendido que se debe poner CUAL ES EL SIGUIENTE elemento.

Es decir uno define node y busca hasta el último elemento y luego lo enlaza con newNode PERFECTO! ESO SE ENTIENDE.

La pregunta es: ¿cuando enlaza list con node? capaz hay algo de la defición que no entiendo

O sea para mi falta un list->next=node; ¿me entendés?
Así como hace node->next=newNode;

¿Por qué no hace falta enlazar de algún modo list con node? yo lo estoy pensando mal y lo sé pero es por alguna estructura o algo que no entendí


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: MAFUS en 7 Mayo 2016, 18:11 pm
No se puede hacer list->next = node porqué node es solo un puntero y no tiene dato.
En la práctica es esto:
Código
  1. int* pint = malloc((sizeof(int));
  2. int* node;
  3.  
  4. node = pint;
  5.  
  6.  

Cuándo haces node = list ya creas la relación. node es list.


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: GGZ en 7 Mayo 2016, 18:18 pm
AAahhh ¡Claro! que tonto, ahora si entendí
Eso era todo lo que quería que me digas no que me expliques el código entero  :xD


Muchas gracias!


Título: Re: [C] Listas enlazadas utilizando arreglos
Publicado por: MAFUS en 7 Mayo 2016, 19:56 pm
Perfecto  ;-) ;-)