realizar una copia profunda en el constructor de copias
Frecuentes
Visto 987 equipos
1
Tengo una pila de clases que se define así:
#ifndef STACK_H
#define STACK_H
#include "MyException.h"
#include <iostream>
using namespace std;
template<class T>
class Stack;
template<class T>
ostream& operator<<(ostream&,Stack<T>&);
template<class T>
class Stack
{
public:
friend ostream& operator<< <T>(ostream&,Stack<T>&);
/*The constructor for the Stack class*/
Stack();
/*The copy constructor*/
Stack(const Stack<T>& other);
Stack<T>& operator=(const Stack<T>& other);
/*The destructor for the stack class*/
~Stack();
void push(const T& el);
T pop();
bool isEmpty();
private:
/*The node class.*/
class Node
{
public:
Node(const T& data, Node* n = 0)
{
element = data;
next = n;
}
T element;
Node* next;
};
/*The top of the stack*/
Node* top;
};
#include "Stack.C"
#endif
Y tengo que realizar una copia profunda en mi constructor de copias. Pero lo que hice fue crear una matriz temporal y copiar todos los elementos en el objeto recibido por el parámetro en la matriz y luego el nodo en la matriz y luego empujarlos al nodo definido en la clase Stack. Así es como lo hice:
template<class T>
Stack<T>::Stack(const Stack<T>& other)
{
top = NULL;
if(other.top == NULL)
{
this->top=NULL;
}
else
{
Node* count;
count= other.top;
int num=1;
while(count->next != NULL)
{
num++;
count = count->next;
}
cout<<"test"<<endl;
T arr[num];
arr[0] = other.top->element;
Node* count2;
count2= other.top;
for(int i = 1 ; i<num; i++)
{
arr[i] = count2->next->element;
count2 = count2->next;
}
T temp;
for(int i =0, j=num-1; i<num/2 ; i++, j--)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
for(int i =0; i<num; i++)
{
push(arr[i]);
cout<<arr[i]<<endl;
}
}
}
Puede suponer que mi push(const T& el) y pop() funcionan bien. ¿Alguien puede ayudarme a realizar una copia profunda?
1 Respuestas
1
No hay ninguna razón para que una matriz haga una copia profunda de una pila. Dado que tiene todos los punteros a los nodos en su cadena de pila actual, simplemente recorra esa lista vinculada. La parte inusual de este algoritmo implica encadenamiento hacia adelante los nuevos nodos a medida que se ingresan y, por lo tanto, conservan el orden de pila original. Hay varias formas de hacer esto, pero prefiero usar un solo puntero a puntero que siempre contiene el dirección del puntero que se rellenará en la siguiente copia.
Stack(const Stack<T>& other)
: top(nullptr)
{
const Node* p = other.top;
Node **pp = ⊤
while (p)
{
*pp = new Node(*p);
p = p->next;
pp = &(*pp)->next;
}
*pp = nullptr;
}
Una vez hecho esto, la pila se replicará en profundidad y conservará el orden de los objetos de origen. Y recomiendo enfáticamente implementar un Node(const Node&)
copy-ctor que copia el elemento de datos , solamente y establece el siguiente puntero en nulo.
¿Cómo funciona?
Al final, esto no es más que una copia de un solo escaneo de una lista con enlaces directos. el puntero pp
siempre contiene la dirección del siguiente puntero al que se le asignará un nuevo nodo. Es importante recordar que el puntero al que se dirige es parte de la lista, no un puntero temporal. Inicialmente pp
se le asigna la dirección del puntero superior, que no es coincidencia que ya esté inicializado en NULL. A partir de ahí, se repite lo siguiente hasta que nos quedemos sin nodos:
- Asigne una copia del nodo de origen actual a
*pp
. Esto significa que el puntero direccionado porpp
recibirá la nueva dirección de nodo. -
Avanzada
pp
mantener la dirección delnext
miembro del mismo nodo que acaba de ser asignado. Este se convierte en el siguiente objetivo para la próxima inserción. - Avanzar el puntero de origen al siguiente nodo de origen.
Esto se repite hasta que nos quedemos sin nodos. En ese tiempo pp
tiene la dirección del pasado nodo next
puntero, que debe asignarse como nulo para que nuestra lista termine correctamente. Ese es el propósito del cierre. *pp = nullptr;
. Con eso, la lista ahora finaliza y el objeto ahora tiene una réplica de la lista vinculada del objeto de origen.
Un poco de alimento para el pensamiento. ¿Qué sucede si la lista de fuentes está inicialmente vacía? ¿Funcionaría esto con una lista circular (respuesta: no, ni siquiera lo intentes)?
Respondido 12 Feb 14, 08:02
Gracias por tu ayuda. Pero recibo errores como: no se puede convertir la pila ::Nodo** a apilar ::Nodo* en Nodo de inicialización pp = &top ..... Conversión definida por el usuario no válida de la pila Nodo para const Stack ::Nodo& *pp=nuevo Nodo(*p)....y otros - beckinho
@beckinho Verifique el código nuevamente. me faltaba un *
on pp
en la publicación inicial. - QuiénesCraig
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c++ copy-constructor deep-copy or haz tu propia pregunta.
Cuando N está en el tamaño de la matriz, no es una buena idea asignarlo en la pila. La primera
while
loop debería ser suficiente para inicializar los nodos en el objeto que se está construyendo. - bobahLo estás haciendo mucho más complicado de lo que deberías... Todo podría hacerse en un bucle while, como dice bobah. - Carl Colijn
@bobah Puse un contador allí para saber cuál es el tamaño de mi pila para poder usarlo en mis bucles for - beckinho
@beckinho: lo siento, quise decir pila de llamadas de función, no tu
Stack
clase. Cuando asigna una gran matriz localT arr[num]
existe la posibilidad de que se produzca un desbordamiento de la pila de llamadas. - bobahNo necesita contar los elementos ni copiarlos en una matriz temporal... simplemente
for (Node* p = other.top; p; p = p->next) push(*p);
- Tony Delroy