我有一个类堆栈,其定义如下:
#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
我必须在我的复制构造函数中执行深层复制。但我所做的是创建一个临时数组并将参数接收的对象中的所有元素复制到数组中,然后将节点放入数组中,然后将它们全部推送到Stack类中定义的节点。我就这样做了:
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;
}
}
}
你可以假设我的推(const T&amp; el)和pop()工作正常。任何人都可以帮我执行深层复制吗?
答案 0 :(得分:1)
没有理由使用数组来深度复制堆栈。由于您拥有当前堆栈链中节点的所有指针,因此只需遍历该链接列表即可。该算法的不寻常部分涉及在输入新节点时正向链接,从而保留原始堆栈顺序。有许多方法可以做到这一点,但我更喜欢使用一个指针到指针始终持有的地址的,将在下副本中填充的指针。
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;
}
完成此操作后,将对堆栈进行深层复制并保留源对象顺序。我强烈建议实现一个Node(const Node&)
copy-ctor,它只复制数据元素 并将下一个指针硬拷贝为空。
如何运作
最后,这只不过是前向链接列表的单扫描副本。指针pp
始终保存将被分配新节点的下一个指针的地址。重要的是要记住它所寻址的指针是列表的一部分,而不是一些临时指针。最初为pp
分配了顶部指针的地址,该指针不巧合地已经初始化为NULL。从那里开始重复以下操作,直到我们用完节点:
*pp
。这意味着pp
寻址的指针将接收新的节点地址。 pp
以保留刚刚分配的节点的next
成员的地址。这将成为下一次插入的下一个目标重复这一过程,直到我们的节点用完为止。那时pp
保存 last 节点的next
指针的地址,应该为我们的列表指定null以正确终止。这就是结束*pp = nullptr;
的目的。这样,列表现在终止,对象现在具有源对象链接列表的副本。
有些值得深思。如果源列表最初为空,会发生什么?这是否适用于循环列表(答案:不,甚至不尝试)。