Problema con las pilas C++

Iniciado por 98Fran, 28 Agosto 2019, 21:28 PM

0 Miembros y 1 Visitante están viendo este tema.

98Fran

Estoy comenzando a ver las pilas y me pareció que parecía igual que un vector de una estructura pero con más parafernalia y mas lioso, en que se diferencia:

Código (cpp) [Seleccionar]
#include <iostream>
#include <cstdlib>

using namespace std;

struct Nodo{
int dato;
Nodo *siguiente;
}

void agregarPila(Nodo *&,int);
int main(){
Nodo *pila = NULL;




cin.get();
return 0;
}

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


de:

Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

struct Nodo{
int dato;
}nodo[2], *pila = nodo //&nodo[0]
//Ahora puedo usar cualquier dato de la plia sin estar restringido al nodo superior

int main(){

cin.get();
return 0;
}


Me parece mejor incluso usar un vector de estructura ya que no estas restringido a ir de forma ascendente. (La única pega que le veo es que tienes que darle un tamaño inicial al vector y si usas de menos estas desperdiciando memoria o si usas de más te quedas corto y no puedes almacenarlo todo)

MAFUS

Una pila es un 'objeto' del que solo puedes ver la cabeza, no es un vector en el que puedes ver todos los elementos.

Imagínate que tienes diferentes platos y cada uno tiene un número diferente escrito en el fondo. Ahora empiezas a apilar los platos. A medida que lo vayas haciendo sólo conocerás un único valor, el que está en el plato de más arriba. Si quieres saber que números hay más abajo deberás sacar platos de la pila pero así cómo los vayas sacando los irás perdiendo, ya no formarán parte de la pila. En un vector todo esto no ocurre.

Pasa por este video, es en Java, pero la base es la misma: https://www.youtube.com/watch?v=-Shr2s0gYao

98Fran

#2
Hace nada he visto los puntero a estructura y ahora estoy viendo lo de las pilas, el concepto de pila ya lo tengo claro, pero lo que no entiendo es para que existe el concepto de pila si al hacer un vector de la estructura te ahorras un montón de pasos y sintaxis liosa a la hora de crear una pila. Sobretodo por el hecho de que el vector no depende del "plato" que este arriba si no que se puede llamar a cualquier "plato" y sin destruir la "pila de platos".

Código (cpp) [Seleccionar]
struct Nodo{
int dato;
}nodo[100], *pila = nodo //&nodo[0]
//Ahora puedo usar cualquier dato de la plia sin estar restringido al nodo superior


Esto hace lo mismo que una pila de 100 nodos pero sin depender de la primera posición y me ahorro todo el procedimiento de ir creando nodos, guardar el dato en int dato, luego vincular el puntero *siguiente al Nodo *pila "El ultimo nodo antes de el", y luego igualar pila al nuevo nodo creado.

Digamos que el concepto de pila y su procedimiento si lo tengo claro, lo que no tengo claro es su utilidad teniendo algo que ya había visto antes como son los vectores de estructura. (De momento solo he visto de C++ todo lo básico hasta punteros y pilas)

K-YreX

No le ves la utilidad porque ves muy complejo el hecho de crear una pila para hacer algo que podrías hacer con un array sin tanta complicación. La realidad es que para usar una pila siempre podemos usar la que alguien se preocupó en crear para la STL. Esta tienes sus funciones optimizadas.
Un buen programador no sólo debe limitarse a resolver un problema sino a hacerlo de la forma más eficaz y eficiente que pueda. Existen ocasiones en las que sólo necesitamos conocer el último elemento que hemos introducido, recuerdo un ejercicio: paréntesis correctos. Este ejercicio podría decir algo tal:

Ejercicio: Paréntesis correctos
Dada una frase u operación matemática, comprobar si la secuencia de paréntesis es correcta.
Una secuencia de paréntesis es correcta si todas las llaves de apertura tienen su correspondiente llave de cierre y nunca aparece una llave de cierre antes que su correspondiente llave de apertura.

Si te apetece puedes intentarlo. Además ya tienes una pista: se hace con pilas. :xD

Lo que estás haciendo ahora es recrear el contenedor <stack> de una forma un poco más cutre pero que sirve para entender cómo funciona. Es un ejercicio típico en programación el crear manualmente contenedores que ya existen (pilas, colas, listas enlazadas, listas doblemente enlazadas, etc).
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

98Fran

#4
Tengo una duda.
Código (cpp) [Seleccionar]
void sacar(Nodo *&pila, int &n){
Nodo *aux = pila;
n = aux.dato;
pila = aux.siguiente;
delete aux;
}


aqui esta el main:

Código (cpp) [Seleccionar]
int main(){
Nodo *pila = NULL;
int dato;
char letra;

do{
cout<<"Digite un numero: ";
cin>>dato;
agregar(pila,dato);

do{
cout<<"\nDesea agregar otro elemento a la pila (Y/N): ";
cin>>letra;
letra = toupper(letra);
cout<<endl;
}while(letra != 'Y' && letra != 'N');

}while(letra == 'Y');

cout<<"\n\nSacando los elementos de la pila: ";

while(pila != NULL){
eliminar(pila,dato);

if(pila != NULL){
cout<<dato<<" , ";
}
else{
cout<<dato<<".\n\nYa se han eliminado todos los datos.";
}
}
cin.get();
return 0;
}


Por que hay que usar -> y no se puede usar "." como en:

Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

struct etapasCorredor{
int horas,minutos,segundos;
}nEtapas[3], *etapa = nEtapas;

void pedirDatos();
int calcularTiempo(int);
void mostrarTiempo(int);

int main(){
int cantidadEtapas = 3;

pedirDatos();
int totalTiempo = calcularTiempo(cantidadEtapas);
mostrarTiempo(totalTiempo);

cin.get();
return 0;
}

void pedirDatos(){

for(int i=0;i<3;i++){
cout<<"Digite tiempo de la etapa ["<<i<<"]: "<<endl;

cout<<"Horas: "; cin>>etapa[i].horas;
cout<<"Minutos: "; cin>>etapa[i].minutos;
cout<<"Segundos: "; cin>>etapa[i].segundos;

cout<<endl;
}

}

int calcularTiempo(int x){
int tiempo;

if(x == 0){
tiempo = etapa[x].horas*3600 + etapa[x].minutos*60 + etapa[x].segundos;
}
else{
tiempo = etapa[x].horas*3600 + etapa[x].minutos*60 + etapa[x].segundos + calcularTiempo(x-1);
}
//2-1-0 -->2 + 1 + 0;

return tiempo;
}

void mostrarTiempo(int tiempo){
int h,min,seg;

h = tiempo/3600;
min = (tiempo-h*3600)/60;
seg = tiempo-h*3600-min*60;

cout<<"\n---------------------------------\n\n";
cout<<"El tiempo total es: "<<endl;
cout<<"Horas: "<<h<<endl;
cout<<"Minutos: "<<min<<endl;
cout<<"Segundos: "<<seg<<endl;

}


PD: Por que siempre que el profesor usa valores como struct o variables globales en el paréntesis de la función (en este caso no hay variables globales pero en la mayoría del curso usa globales). Que diferencia hay con simplemente no ponerlas y usar el mismo código (en este caso lo entiendo por que al *pila estar dentro de la funcion main() si no pasamos el puntero por referencia despues de que acabe la funcion pila = nuevo_nodo se borraria y pila seguiria apuntando a NULL. Me refiero más a esto:

Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

int x = 0;

void cambiar(int&);

int main(){
cout<<"Antes: "<<x<<endl;
cambiar(x);
cout<<"Depues: "<<x<<endl;

cin.get();
return 0;
}

void cambiar(int &x){
x=10;
}


y lo mismo he visto en estructuras, por ejemplo un vector de estructura y usarlo sin  declararlo en el paréntesis tipo:

Código (cpp) [Seleccionar]
void mostrar(){
cout<<prueba[3].dato; //En una función anterior he metido valores dentro de dato
}


Pd2: le tuve que añadir
Código (cpp) [Seleccionar]
cin.ignore(1,'\n'); por que si ponia "yy" se ponía en modo bucle infinito no se por qué.

K-YreX

No estoy seguro de haberte entendido así que te explico más o menos:
Citar
Por que hay que usar -> y no se puede usar "."
El operador -> no es necesario. Quiero decir que no es un operador que haga algo que no puedas hacer con otro. El operador flecha se creó para evitar el punto y asterisco juntos.
Código (cpp) [Seleccionar]

struct Persona{
    string nombre;
    int edad;
};

int main(){
    Persona persona1;
    Persona *punteroPersona = &persona1;

    cout << "Nombre persona: ";
    getline(cin, punteroPersona->nombre); // equivale a: getline(cin, (*punteroPersona).nombre)
    //...
}

Es decir cuando estamos usando un puntero <punteroPersona> y tenemos que:
  • Acceder al dato del puntero: <*punteroPersona>
  • Acceder al dato miembro de ese datos: <(*punteroPersona).nombre>
    Podemos directamente usar el operador flecha para que quede mejor a la vista: <punteroPersona->nombre>


    Respecto al otro tema: las variables globales no es necesario pasarlas como parámetros ya que ya son conocidas en todo el programa y por tanto se pueden usar en cualquier parte de este. Supongo que si las pasa como parámetros será para poder ver en el <main> qué variable es la que está pasando a la función o por si te da por cambiar el nombre de la variable global, no tener que cambiarlo x veces en las funciones, sólo lo cambias en el parámetro y listo.
    De todas formas es mejor no usar variables globales ya que puedes tener una global y una local que se llamen igual y en una función prepararla por estar trabajando con la que no querías trabajar. Por eso es más seguro limitar su uso a lo imprescindible.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

98Fran

#6
Con los ejemplos que he visto de puntero a estructura no ponía la -> por que todos los ejercicios que había visto usaba un puntero al vector estructura y poniendo por ejemplo:
Código (cpp) [Seleccionar]
cout<<"Digite su nombre: ";
<<cin.getline(persona[i].nombre,30,'\n');


Se guardaba sin problemas y no hacía falta usar ->. Supongo que es por que:
Código (cpp) [Seleccionar]
persona[i] //equivales a
*(personas + i)
Y ya tiene el * implícito en el nombre.

PD: Los punteros me dan mucho dolor de cabeza xD. Con tus explicaciones poco a poco me estoy volviendo en un Master de los punteros jajaja.

98Fran

Por que al seleccionar la opción 3 se salta los breaks???
Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

struct Nodo{
char dato;
Nodo *siguiente;
};

void menu(Nodo *&);
void agregar(Nodo *&);
void mostrar(Nodo *);
void salir(Nodo *&);

int main(){
Nodo *pila = NULL;

menu(pila);
agregar(pila);
mostrar(pila);
salir(pila);

cin.get();
return 0;
}

void menu(Nodo *& pila){
int n;

do{
cout<<"1. Insertar un caracter a la pila"<<endl;
cout<<"2. Mostrar todos los elementos de la pila"<<endl;
cout<<"3. Salir\n";
cin>>n;
cin.ignore();
switch(n){
case 1: agregar(pila); break;
case 2: mostrar(pila); break;
case 3: salir(pila); break;
}
}while(n != 3);
}

void agregar(Nodo *&pila){
Nodo *nuevo_nodo = new Nodo();
cout<<"\nDigite un nuevo Caracter: ";
cin>>nuevo_nodo->dato;
cin.ignore();
nuevo_nodo->siguiente = pila;
pila = nuevo_nodo;
}

void mostrar(Nodo *pila){
Nodo *aux = pila;
cout<<"\nLos elemmentos de la pila son: ";

while(aux != NULL){
cout<<aux->dato<<" , ";
aux = aux->siguiente;
}

cout<<endl;
delete aux;
}

void salir(Nodo *&pila){

while(pila != NULL){
Nodo *aux = pila;
pila = aux->siguiente;
delete aux;
}
}
;

Si uso la opción 2 de mostrar no salta la opción 1, pero si ejecuto el caso 3 se ejecutan todos los casos, que me estoy perdiendo? (y en la función salir() no estoy llamando a las otras 2 funciones).

98Fran

Ya esta resuelto, soy muy tonto xD.
Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

struct Nodo{
char dato;
Nodo *siguiente;
};

void menu(Nodo *&);

}


Las había puesto antes de hacer el menu y cuando lo hice se me olvido quitarlas xD