我刚刚实施了链接列表。它工作得非常好,但即使很难我也看到了我无法在Node上创建工作析构函数的符号,这就是为什么它在代码中没有实现。
请查看完全正常的代码,如果你复制它就行了。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
答案 0 :(得分:1)
当delete
与先前分配的指向链表的指针一起使用时,或者当链表变量超出范围时(例如,从a返回时,本地变量被销毁),将调用链表析构函数。功能)。
链表的析构函数应负责释放先前为节点保留的内存(即使用add
操作)。因此,基本上,您需要遍历节点列表并对每个节点应用delete
操作。有一个小技巧:当您要删除节点时,必须注意不要丢失指向下一个元素的指针(当删除节点时,您无法确定next
成员是否仍然有效)。
答案 1 :(得分:1)
我建议你从实现List
的析构函数开始。由于您使用new
动态分配了内存,因此应使用delete
释放内存。 (如果您使用new[]
,则为delete[]
):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
一旦你有了正确的析构函数,你应该尝试复制构造函数是否正确:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
您会发现您的复制构造函数错误,并导致您的应用程序崩溃。为什么?因为复制构造函数的目的是创建 new 对象作为现有对象的副本。您的复制构造函数只是复制指针,假设sizeof(Node*)
等于sizeof(int)
。它应该是这样的:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
此外,您的函数remove
是错误的,因为它“删除”对某个节点的引用,但从不释放此节点所在的内存。应该调用delete
以释放这段记忆。
“我需要在节点上实现工作析构函数” - 不,你没有。节点本身不分配任何内存,因此它不应释放任何内存。节点不应该负责销毁Node* next
,也不应该清理存储它的内存。不要实现析构函数也不要复制Node的构造函数。您还想阅读:What is The Rule of Three?
“让列表对节点友好,所以我不必使用getNext()” - 你想在Node类中说class List
是friend
:
class Node
{
friend class List; // <-- that's it
请注意,从您包含代码的这5个标头中只需要一个:<iostream>
。
另请注意,在文件开头写using namespace std;
被视为不良做法,因为它可能会导致某些类型的名称变得模糊不清。在小范围内明智地使用它或改为使用std::
前缀。
答案 2 :(得分:0)
如果你想为你的Node创建一个析构函数,它实际上应该很简单。
这是:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
这很简单:)
基本上,在删除Node之前,如果next不为空,我们将删除next,这将再次调用next的析构函数,如果next-&gt; next不为空,则再次调用析构函数
然后最后所有节点都被删除。
递归处理整个事情:)