The answer depends on the type of list you use and the semantics of the operation you want to implement.
As Vicente Oyanedel said, it may be a change in the last node of the first list, so that it points to the first node of the second list.
Lista1 -> n1 -> n2 -> NULL
Lista2 -> na -> nb -> NULL
Litsa1 (concatenada) -> n1 -> n2 -> na -> nb -> NULL
According to this, the semantics is to add the elements of the second list to the first one. The problem is that you have several lists pointing to the same nodes, which is known as aliasing
. You should think if it is convenient to allow the aliasing
or in your application this would be wrong, and program accordingly.
For example, a mishandling of the aliasing
would occur if you create a destructor that removes the complete list, freeing the memory of its nodes, after having concatenated it to another list.
// Se crea una lista con los nodos 1, 2, 3
Nodo * lista1 = new Lista();
lista1->add(1, 2, 3);
// Se crea una lista con los nodos 4 y 5
Nodo * lista2 = new Lista();
lista2->add(4, 5);
// Se concatena: ahora las dos listas apuntan a 4 y 5
lista1->concatenar(lista2);
// Imprimimos las listas
lista1->print(); // lista1: 1, 2, 3, 4, 5
lista2->print(); // lista2: 4, 5
// Liberamos memoria de los nodos de lista2 (4 y 5)
delete lista2;
// Imprimimos la primera lista
lista1->print(); // error en tiempo de ejecución
When trying to access memory areas that have already been released, a runtime error would occur.
Another option, which I prefer, is to create a function that given two lists, create a new one and insert copies of the nodes of the two. Thus the aliasing
is not allowed. This would be accompanied by a function addNodo
, that adds a node to the desired list, previous copy of the node.
In any case, the option to use is your decision, but you have to be consistent at the time of scheduling so that there are no problems with null pointers or liberated zones but still inaccessible.
I also think that it is better to define Nodo
as class
, and not as struct
, since, after all, it is a class with public members by default, encapsulating the behavior of a node and a separate list.
Well, I have my node like this:
class Nodo {
friend class Lista;
private:
int valor;
Nodo * sig;
public:
Nodo(int v);
~Nodo();
};
And my list like this:
class Lista {
private:
Nodo * primero;
Nodo * ultimo;
int elementos;
public:
Lista();
~Lista();
void addNodo(Nodo * nodo);
Lista * concatenar(Lista * l);
};
As I have said, the addNodo
function copies the node and inserts it into the list, in such a way that the aliasing
is prevented.
The concatenarListas
function made it static, it receives two lists and returns a new list that contains copies of the nodes of both.
The concatenation code with copy is:
Lista * Lista::concatenar(Lista * l) {
if (l == NULL) throw "Error: lista nula";
Lista * lista = new Lista();
Nodo * nodo = this->primero;
while (nodo != NULL) {
lista->add(nodo);
nodo = nodo->sig;
}
nodo = l->primero;
while (nodo != NULL) {
lista->add(nodo);
nodo = nodo->sig;
}
return lista;
}
This function is based on the function addNodo
, which does not allow the aliasing
, and that is like this:
void Lista::add(Nodo * n) {
if (n == NULL) throw "Error: nodo nulo";
Nodo * copia = new Nodo(n->valor);
if (elementos == 0) {
primero = copia;
ultimo = copia;
}
else {
ultimo->sig = copia;
ultimo = copia;
}
elementos++;
}