0

Estoy estudiando pilas en C++ y por mas que intento hallar la logica no logro comprenderlo, vi una pregunta aqui y me ayudo un poco pero no entiendo completamente.

struct Nodo{
    int dato;
    Nodo *siguiente;

};

int main(){
Nodo *pila = NULL;

}

void agregarPila(Nodo *&pila, int n){
    Nodo *nuevo_nodo = new Nodo();
    nuevo_nodo->dato = n;
    nuevo_nodo->siguiente = pila;
    pila = nuevo_nodo;
}

Entiendo primero se crea al estructura donde se guardaran los datos, de declara el puntero tipo Nodo en Nulo que sera el tope de la pila, mando el valor de N1 y n2 a la funcion agregarPila. Dentro de la funcion recibe la pila y el valor enviado a la pila. Se crea el puntero tipo Nodo llamado *nuevo_nodo y se reserva memoria, el puntero recibe el dato recibido n y nuevo_dato->siguiente ahora es nulo. Pero la ultima parte es la que no logro entender correctamente pila = nuevo_nodo;

La pila ahora tiene la posicion de nuevo_nodo, pero al enviar el segundo dato no entiendo como es que se guardo el dato anterior n1 si de nuevo esta declarando *nuevo_nodo, no se reemplazaria al final quedando solo el ultimo dato enviado? por ejemplo enviar 1,2,3,4. No entiendo como se van guardando quedando 1 2 3 4 NULL. Se que debe ser algo sencillo de entender pero nunca habia visto pilas y no logro comprender como funciona esta ultima parte

Marco Medina
  • 187
  • 1
  • 9
  • Ten encuenta que se estra trabajando con punteros o sea con direcciones de memoria. La clave esta en las dos lineas ultimas, la primera vez , nuevo_nodo->siguiente es nulo porque la pila tiene direccion nula. La segunda vez nuevo_nodo->siguiente apuntara a la pila (que ya tiene un dato) aqui es donde no se suelta la cadena (por asi decirlo de la pila) pues el nuevo nodo tendra la direccion de la pila y cuando el nuevo nodo apunte a la pila (en la ultima linea) la pila tendra la direccion del nuevo nodo pero ademas esta pila tendra la direccion anterior que tenia la pila . – Santiago Arteaga Jul 27 '19 at 19:20
  • para que te puedas dar una idea aqui te dejo un video explicativo. https://youtu.be/z7GPtobcw6U – Santiago Arteaga Jul 27 '19 at 19:23
  • "*Vi una pregunta aquí y me ayudo un poco pero no entiendo completamente*" Estaría bien conocer la pregunta que viste. – PaperBirdMaster Jul 29 '19 at 07:37

1 Answers1

1

Nunca había visto pilas y no logro comprender como funciona esta ultima parte.

Cuando esto sucede, hazte con papel y lápiz y ¡ponte a dibujar!1


Veamos la función que genera dudas:

void agregarPila(Nodo *&pila, int n){ /* 1 */
/* 2 */    Nodo *nuevo_nodo = new Nodo();
/* 3 */    nuevo_nodo->dato = n;
/* 4 */    nuevo_nodo->siguiente = pila;
/* 5 */    pila = nuevo_nodo;
}

¿Cómo actuará la función en la primera llamada?

  1. Sabemos que al iniciar el programa pila apunta a NULL:

    pila --> NULL
    
  2. Creamos un nuevo nodo y guardamos su dirección de memoria en nuevo_nodo:

    pila --> NULL
    nuevo_nodo --> +----- Nodo ------+
                   |     dato: ?     |
                   |   siguiente: ---+--> ?
                   +-----------------+
    
  3. Le guardamos en dato el valor recibido (uso n0 como valor porque es el n de la primera llamada):

    pila --> NULL
    nuevo_nodo --> +----- Nodo ------+
                   |     dato: [n0]  |
                   |   siguiente: ---+--> ?
                   +-----------------+
    
  4. Hacemos que el siguiente apunte donde apunta pila, ergo: ambos apuntan a NULL:

    nuevo_nodo --> +----- Nodo ------+
                   |     dato: [n0]  |
                   |   siguiente: ---+--> NULL <-- pila
                   +-----------------+
    
  5. Hacemos que pila apunte a donde apunta nuevo_nodo:

    nuevo_nodo --> +----- Nodo ------+ <-- pila
                   |     dato: [n0]  |
                   |   siguiente: ---+--> NULL
                   +-----------------+
    

Esto finaliza la primera llamada ¿Cómo serán las siguientes?

  1. Sabemos en la segunda llamada a agregarPila, pila apunta a el nodo creado en la llamada anterior:

    pila --> +----- Nodo ------+
             |     dato: [n0]  |
             |   siguiente: ---+--> NULL
             +-----------------+
    
  2. Creamos un nuevo nodo y guardamos su dirección de memoria en nuevo_nodo:

    pila --> +----- Nodo ------+
             |     dato: [n0]  |
             |   siguiente: ---+--> NULL
             +-----------------+
    nuevo_nodo --> +----- Nodo ------+
                   |     dato: ?     |
                   |   siguiente: ---+--> ?
                   +-----------------+
    
  3. Le guardamos en dato el valor recibido:

    pila --> +----- Nodo ------+
             |     dato: [n0]  |
             |   siguiente: ---+--> NULL
             +-----------------+
    nuevo_nodo --> +----- Nodo ------+
                   |     dato: [n1]  |
                   |   siguiente: ---+--> ?
                   +-----------------+
    
  4. Hacemos que el siguiente apunte donde apunta pila, ergo: ambos apuntan al Nodo creado en la llamada anterior:

    nuevo_nodo --> +----- Nodo ------+    pila --> +----- Nodo ------+
                   |     dato: [n1]  |             |     dato: [n0]  |
                   |   siguiente: ---+-----------> |   siguiente: ---+--> NULL
                   +-----------------+             +-----------------+
    
  5. Hacemos que pila apunte a donde apunta nuevo_nodo:

    nuevo_nodo --> +----- Nodo ------+ <-- pila    +----- Nodo ------+
                   |     dato: [n1]  |             |     dato: [n0]  |
                   |   siguiente: ---+-----------> |   siguiente: ---+--> NULL
                   +-----------------+             +-----------------+
    

Las llamadas sucesivas se comportan igual.

Problemas del código.

Es recurrente en el sitio StackOverflow en Español ver preguntas con este error, es muy común confundir los elementos (Nodos) con la colección (Listas, Pilas, Árboles). Ha Su c e di do M o nt on e s De Ve ce s. Un Nodo es un Nodo no una pila, así que no deberías llamar pila a un puntero a Nodo.

Por otro lado es un lenguaje multiparadigma, así que no existe la obligación de usar un paradigma concreto pero… es conocido por sus funcionalidades de programación orientada a objetos así que ¿por qué no usarlas?

Siguiendo los consejos anteriores el código podría parecerse a:

struct Pila
{
    void agregar(int valor) {
        tope = new Nodo{valor, tope};
    }
private:

    struct Nodo {
        int valor = 0;
        Nodo *siguiente = nullptr;
    };

    Nodo *tope = nullptr;
};

int main() {

    Pila p;
    p.agregar(0);
    p.agregar(1);
    p.agregar(2);

    return 0;
}

  1. No voy a mostrar mis habilidades pictóricas, yo usaré ascii art.
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82