Por lo que veo estás programando en C++. Has de saber entonces que
lo puedes dejar en simplemente en
Que va a funcionar perfectamente. De hecho, el typedef sirve única y exclusivamente para definir alias y su uso es "typedef <tipo> <alias>" y el uso que tu le estás dando es "typedef <tipo>".
Esto en C se usaría así:
O así:
Código C:
Ver originalstruct vehiculo
{
};
typedef struct vehiculo vehiculo;
Y la ventaja que obtienes con esta sintaxis (ojo, para el caso de struct y C) es que ya no es necesario usar struct para referirte a la variable.
Peeeero como hemos dicho, en C++ esto ya no es necesario, luego la siguiente declaración funciona igual de bien y es más limpia:
Aun así, no es por tocar mucho las narices pero yo esa clase la dividiría en dos: Por un lado los datos propios del vehículo y por otro la gestión de nodos:
Código C++:
Ver originalstruct vehiculo
{
string matricula;
bool estado ;
char tipo;
string marca;
string modelo;
};
struct nodo
{
vehiculo datos;
nodo* sig;
};
En programación conviene no mezclar churras con merinas para evitar errores. También estaría bien, dado que tienes tipos nativos (bool, char, un puntero...) implementar los constructores por defecto para evitar tener que hacer inicializaciones manuales so pena de dejar basura en las clases:
Código C++:
Ver originalstruct vehiculo
{
string matricula;
bool estado ;
char tipo;
string marca;
string modelo;
// opcion 1 para el constructor por defecto
vehiculo() : estado(false), tipo(' ')
{}
// opcion 2: son equivalentes
vehiculo()
{
estado = false;
tipo = ' ';
}
};
struct nodo
{
vehiculo datos;
nodo* sig;
nodo() : sig(0)
{}
};
Otro consejo que te doy, pero depende también de si es requisito del ejercicio hacerlo así o no, es que en tu caso el tipo no debería ser un char sino un enumerado:
Código C++:
Ver originalenum TipoVehiculo
{
Ninguno,
Gasolina,
Diesel,
Moto,
Industrial
};
struct vehiculo
{
TipoVehiculo tipo;
};
¿Por qué? En primer lugar porque así queda claro que esa variable no admite cualquier valor... ¿qué pasa si esperas encontrar una 'G' de gasolina y en alguna parte del programa se pone una 'g'? ¿Te dedicas a comprobar las dos combinaciones? ¿Y si te equivocas y pones una 'h' que está justo al lado del teclado? Con un enumerado no tienes esos problemas... de hecho si intentas hacer "tipo=gaoslina" el compilador te marcará un error en esa línea, ayudándote en la tarea de evitar errores en el código.
Si te preocupa la entrada de datos del usuario, para eso puedes usar bien una función:
Código C++:
Ver originalTipoVehiculo ConvertirATipoVehiculo(char c)
{
switch( c )
{
case 'G':
return Gasolina;
default:
return Ninguno;
}
}
Seguimos:
Código C++:
Ver originaltypedef struct Cola
{
struct vehiculo *cabecera;
struct vehiculo *ultimo;
}*lacola;
Dos cosas mal que veo en este código:
- Si la lista es enlazada simple no tiene sentido alguno que tengas un puntero al último elemento de la lista.
- Si creas un alias de un puntero por favor que el nombre indique esa característica de alguna forma.
Entre otras cosas puedes hacer que tu programa funcione sin hacer que "lacola" sea puntero. Para eso inventaron las referencias.
Yo la declaración de esa clase la dejaría así (asumiendo que haces también el cambio referente a separar la clase vehiculo):
Código C++:
Ver originalstruct Cola
{
nodo*cabecera;
Cola() : nodo(0)
{}
// o si lo prefieres:
Cola()
{ nodo = 0; }
};
Por otro lado no se si has visto o conoces de alguna manera los destructores y los métodos miembros de la clase, que te serían de gran utilidad. En este tema no me enrollo más porque entonces no me entraría todo en el mensaje, pero si quieres más detalles tu pregunta.
Bueno, el caso es que hemos dicho que no hace falta usar un puntero para "lacola" ¿Cómo es eso? Más o menos así:
Código C++:
Ver original// En C++ no hace falta poner void en la lista de parámetros
Cola crearCola()
{
Cola cola
// No entiendo por qué la cola ha de tener de primeras un vehículo
// Lo suyo es que inicialmente estuviese vacía
// cola.cabecera = new struct vehiculo;
// Esta línea estaba mal. Si la lista solo tiene un elemento por qué creas dos nodos?
// co->ultimo = new struct vehiculo;
// y para colmo de males la reserva anterior la pierdes creando lagunas de memoria
// co->ultimo = NULL;
// como las clases ahora tienen constructores, esto sobra
// co->cabecera->sig = NULL;
return cola;
}
Es decir, esta función no es necesaria:
Código C++:
Ver originalint main()
{
// Y ya está, ya son colas usables
Cola gasolina, diesel, moto, industrial;
}
Otro ejemplo con referencias:
Código C++:
Ver originalbool colaVacia(Cola& laco)
{
// Las referencias usan el punto en vez de la flecha
return (laco.ultimo == NULL);
// Si compilas con C++11 (estándar del 2011) también puedes dejarlo así
return (laco.ultimo == nullptr);
}
// Las siguientes las puedes actualizar tu
Es de agradecer no usar memoria dinámica si podemos evitarlo porque su uso es complicado y es facil meter la pata y usar un puntero que no apunta a ningún sitio o dejarnos memoria sin liberar. Como por ejemplo...
Código C++:
Ver originalvoid volver(lacola laco)
{
struct vehiculo *nodo_aux;
nodo_aux = new struct vehiculo;
nodo_aux = laco->cabecera->sig; // <<--- AQUI!!!
laco->cabecera->sig = nodo_aux->sig;
laco->ultimo->sig = nodo_aux;
nodo_aux->sig = NULL;
laco->ultimo = nodo_aux;
}
Fíjate que justo en la linea anterior has creado un objeto con new... si después asignas otro valor a ese puntero has perdido la memoria reservada con new. Ese new lo puedes eliminar con mucho cariño.
Te explico: Que uses un puntero no quiere decir que SIEMPRE tengas que hacer un new. Esto se hace únicamente cuando quieres crear un objeto nuevo. Si lo que pretendes es usar el puntero para acceder a elementos ya existentes no hay que usar new:
Código C++:
Ver originalint* miClase1 = new int;
int miClase2 = 2;
*miClase = 1;
int* ptr = miClase; // ptr y miClase apuntan al mismo elemento
std::cout << *ptr << *miClase << std::endl; // imprime 11
*ptr = 10;
std::cout << *ptr << *miClase << std::endl; // imprime 1010
// Ahora el puntero apunta a miClase2
ptr = &miClase2;
std::cout << *ptr << miClase2 << std::endl; // imprime 22
// Por cada new tenemos que poner un delete
delete miClase;
Repasemos la implementación de la función quitar.
Código C++:
Ver originalvoid quitar(lacola laco)
{
// he quitado el código porque no me entraba el mensaje
}
Vale, antes hemos visto que tener un puntero al último en una lista enlazada simple es un absurdo. Aquí vas a ver uno de las razones: Tener información redundante implica tener que actualizarla correctamente so pena de tener errores. Dicho en cristiano: "Si sabes que la lista termina cuando el "sig" de un nodo es 0... ¿Por qué te complicas usando cola->ultimo?
Aparte de eso tienes variables que no usas ni necesitas para nada:
Código C++:
Ver originalvoid quitar(Cola& laco)
{
if(colaVacia(laco))
cout << "LA COLA ESTA VACIA" << endl;
else
{
nodo* temp = laco.cabecera;
laco.cabecera = temp->cabecera;
delete temp;
}
}
Y ya está, ya has quitado el primer elemento de la cola. Simplemente hay que hacer que cabecera apunte al segundo elemento y después borrar el nodo que queda huérfano. El sistema va a funcionar porque sabes que SIEMPRE se va a cumplir que el último nodo de la lista tiene su sig apuntando a 0 o NULL o nullptr, como prefieras.
Código C++:
Ver originalvoid volver(lacola laco)
{
struct vehiculo *nodo_aux;
nodo_aux = new struct vehiculo;
nodo_aux = laco->cabecera->sig;
laco->cabecera->sig = nodo_aux->sig;
laco->ultimo->sig = nodo_aux;
nodo_aux->sig = NULL;
laco->ultimo = nodo_aux;
}
Otro cacao descomunal. Viendo un poco tu programa deduzco que esta función cola el primer nodo al final de la lista... veamos:
Código C++:
Ver original// estado inicial: A->B->C->D
// nodo_aux = B
nodo_aux = laco->cabecera->sig;
// A->C->D
laco->cabecera->sig = nodo_aux->sig;
// A->C->D->B
laco->ultimo->sig = nodo_aux;
¿No es lo que esperabas, verdad?
Código C++:
Ver originalvoid volver(Cola& laco)
{
nodo* nodo = laco.cabecera;
// Si está vacía no podemos tocar nada.
// Si solo tiene un elemento tampoco porque el nodo es a la vez el primero y el último
if( nodo != 0 && nodo ->sig != 0)
{
// Ahora la lista empieza en el segundo nodo
laco.cabecera=nodo->sig;
// Navegamos hasta el final de la lista
nodo* ptr = laco.cabecera;
while(ptr->sig)
ptr = ptr->sig;
// ptr apunta al último nodo de la lista. Colocamos detrás el que era el primer nodo y actualizamos su sig.
ptr->sig = nodo;
nodo->sig = 0;
}
Y bueno, recapitulando. Tus mayores problemas están en la gestión de la cola y el uso de punteros. En eso tienes que ponerte las pilas.
También sería interesante y recomendable que empezases a usar el depurador de código. Es una herramienta imprescindible para programar. Puede costar empezar a manejarla pero en seguida verás lo útil que resulta y pronto pasará a ser imprescindible para ti.
Un saludo.