如何正确实现“三大”:单链表(C++)
How do I Implement the Big Three Correctly: Singly Linked List (C++)
我正在编写一个程序,该程序包含一个用于保存购物清单的单链表。每个节点都有项目名称、数量和数量描述(例如鸡蛋的打数)。除析构函数外,程序中的所有工作项都能找到。不过我似乎找不出它有什么毛病。
驱动程序将执行到代码为return 0;
的末尾,然后调用析构函数并在delete current;
行上停止,并显示消息:
"项目14.exe:
0xC0000005
:读取位置0xFEEEFEE2
时发生访问冲突,0x0FC7A9E8
(msvcr120d.dll
)处出现未处理的异常。".
我已经在下面发布了三大函数的实现。默认构造函数将两个指针(first
、last
)初始化为null
,将nodeCount
初始化为0
。
我似乎找不出问题。有什么帮助吗?
List::List(const List& b)
{
Node* newNodePtr = new Node;
Node* nodeCopy = b.first;
newNodePtr = nodeCopy;
first = newNodePtr;
last = newNodePtr;
nodeCount++;
nodeCopy = nodeCopy->getNext();
while (last != b.last)
{
Node* newNode = new Node;
newNode = nodeCopy;
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
nodeCount++;
nodeCopy = nodeCopy->getNext();
}
}
List::~List()
{
Node* current = first;
while (current != nullptr)
{
Node* _next = current->getNext();
delete current;
current = _next;
}
first = nullptr;
last = nullptr;
}
List& List::operator=(const List& rho)
{
Node* current = first;
while (current != nullptr)
{
Node* _next = current->getNext();
delete current;
current = _next;
}
first = nullptr;
last = nullptr;
Node* newNodePtr = new Node;
Node* nodeCopy = rho.first;
newNodePtr = nodeCopy;
first = newNodePtr;
last = newNodePtr;
nodeCount++;
nodeCopy = nodeCopy->getNext();
while (last != rho.last)
{
Node* newNode = new Node;
newNode = nodeCopy;
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
nodeCount++;
nodeCopy = nodeCopy->getNext();
}
return *this;
}
编辑:我还添加了我的push_back函数,如下所示:
void List::push_back(Node* newNode)
{
if (first == nullptr)
{
first = newNode;
last = newNode;
}
else
{
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
}
nodeCount++;
}
好吧,我想我已经想通了。这个代码似乎有效,它适合我的教授提供的驱动程序。下面我介绍了三大函数以及它们调用的所有其他函数:
List::List(const List& b)
{
this->copyList(b);
}
List::~List()
{
this->clearList();
}
List& List::operator=(const List& rho)
{
this->clearList();
this->copyList(rho);
return *this;
}
void List::clearList()
{
Node* current = first;
while (current != nullptr)
{
current = pop_front();
delete current;
current = first;
}
first = nullptr;
last = nullptr;
}
void List::copyList(const List& b)
{
first = nullptr;
last = nullptr;
nodeCount = 0;
Node *headNode = b.getFirst();
while (headNode != nullptr)
{
string des = headNode->getDescription();
string qNa = headNode->getQuantityName();
int qNu = headNode->getQuantityNumber();
Node* newNode = new Node(qNu, qNa, des);
push_back(newNode);
headNode = headNode->getNext();
}
}
Node* List::pop_front()
{
Node* saveFirst = first;
first = first->getNext();
nodeCount--;
return saveFirst;
}
void List::push_back(Node* newNode)
{
if (nodeCount == 0)
{
first = newNode;
last = newNode;
}
else
{
Node* currentNode = last;
currentNode->setNext(newNode);
last = newNode;
}
nodeCount++;
}
这可能无法解决您的确切问题,但如果您有您提到的函数,那么复制构造函数的伪代码会是这样的。
List::List(const List& b)
{
Node *headNode = b.getHeadNode();
while (headNode != NULL)
{
push_back(headNode->getDataFromNode());
headNode = headNode->getNextNode();
}
}
所以基本上,简而言之就是整个复制构造函数。您基本上是从列表中的第一个节点开始,从该节点获取数据,然后调用push_back()来添加新数据。我假设push_back()完成了创建一个节点、向其中添加数据并将其正确放置在列表后面的所有棘手工作。
注意这个实现是多么的小、紧凑和直观。我们知道,要创建一个链表的副本,我们所需要做的就是首先确保列表是空的(对于一个新对象来说是空的),然后不断地将旧列表中的项添加到新列表中。由于push_back()将一个项添加到列表中(并且具有创建节点并将其链接到结束节点的所有复杂性),我们以一种智能的方式使用它来创建副本。
请注意,您还需要一个赋值运算符来配合复制构造函数。示例中的赋值运算符只是简单地调用clear()(如果您有这样的函数)来删除所有节点,然后再继续。
请记住,所有这些都需要push_back()函数完美地工作。它应该知道如何正确地处理在空和非空列表末尾的插入。
编辑:
如果您的驱动程序代码确实在push_back之前创建了新节点(因此push_back不会分配新节点),那么可以使用替代代码:
List::List(const List& b)
{
Node *headNode = b.getHeadNode();
while (headNode != NULL)
{
Node *newNode = new Node(headNode->getDataFromNode());
push_back(newNode);
headNode = headNode->getNextNode();
}
}
在替代版本中,我假设可以使用数据作为参数来创建新节点的构造函数。我个人不喜欢让push_back()不完成创建节点的所有工作的设计,但这是另一个问题。
它至少在一定程度上取决于调用析构函数时第一个指向的是什么。
您的代码没有复制节点的内容。相反,它只是在操纵指针,因此,正如dyp所指出的,您有一个泄漏:Node*newNodePtr=新节点;节点*nodeCopy=b.first;newNodePtr=节点复制;
你可能想了解一下"副本交换"的习惯用法。复制和交换习语是什么?
- 反向给定链表中的K节点
- 如果没有malloc,链表实现将失败
- 文本文件中的单词链表
- 努力将整数转换为链表。不知道我在这里做错了什么
- 链表,反向函数,数据结构
- 使用std::list创建循环链表
- 链表的泛型函数remove()与成员函数remove)
- 为什么不能修改对象中的值?另外,我如何改进此链表?
- 我们可以删除链表中静态内存中的节点吗
- C++,指针数组,指向双链表中的条目
- 链表中写入访问冲突的未知原因
- 如何修复链表类实现的未处理异常0xDDDDDDDD
- 打印所有链表的元素 (C++)
- 错误:需要类名(链表c++)
- 为什么C中的通用链表中存储的数据已损坏
- C++ 创建包含链表和字符串的对象的链接列表时出错
- 链表c++插入,所有情况都已检查,但没有任何工作
- 链表,将列表复制到另一个列表
- 为什么C++对链表中的下一个节点使用指针,而像 C# 或 Java 这样的语言只使用类 Node 的名称?
- 对单向链表进行排序时出现运行时错误