我正在实现一个从未排序的双向链表中删除重复项的函数。我删除了其他功能,以保持代码简短和清晰。请假设其他函数(如InsertFront)可以正常工作。
删除副本时,我无法在我的Node类中附加prev指针。我不确定我是否正确附加了前缀指针。我目前遇到了一个段错误。谢谢。
这是我的头文件。 dlinkedlist.h
#ifndef _DLINKEDLIST_H_
#define _DLINKEDLIST_H_
#include <cstdlib>
#include <stdexcept>
#include <string>
#include <iostream>
using namespace std;
template <class T>
class Node
{
public:
T data;
//string data;
Node<T>* prev;
Node<T>* next;
// default constructor
Node(T value)
{
data = value;
prev = NULL;
next = NULL;
}
};
// DLinkedList class definition
template <class T>
class DLinkedList
{
private:
// DLinkedList private members
int size; // number of items stored in list
Node<T>* front; // references to the front
Node<T>* back; // and back of the list
DLinkedList();
DLinkedList(const DLinkedList& ll);
~DLinkedList();
void RemoveDuplicates();
}
这是我的实现dlinkedlist.cpp
#ifdef _DLINKEDLIST_H_
#include <cstdlib>
#include <stdexcept>
#include "dlinkedlist.h"
#include <string>
#include <iostream>
using namespace std;
template <class T>
void DLinkedList<T>::RemoveDuplicates() {
Node<T> *current, *runner, *dup;
current = front;
cout << "Removing the duplicates..." << endl;
while (current != NULL && current->next != NULL) {
runner = current;
while (runner->next != NULL) {
if(current->data == runner->next->data) {
dup = runner->next;
runner->next = runner->next->next;
runner->next->prev = runner->next->prev->prev; //trying to connect to previous node. Works without this line.
delete dup;
}
else {
runner = runner->next;
}
}
current = current->next;
}
}
这是我的测试文件。 TEST.CPP
#include <cstdlib>
#include <iostream>
#include <string>
#include "ccqueue.h"
#include "dlinkedlist.h"
#include "ticket.h"
using namespace std;
void LLTest();
int main()
{
cout << "\nEntering DLinkedList test function..." << endl;
LLTest();
cout << "...DLinkedList test function complete!\n" << endl;
return 0;
}
void LLTest()
{
// default constructor, InsertFront, InsertBack, ElementAt
DLinkedList<int> lla;
lla.InsertFront(2);
cout << "-------------------------------------------------\n";
lla.InsertBack(5);
lla.InsertBack(10);
lla.InsertBack(2);
cout << "-------------------------------------------------\n";
lla.RemoveDuplicates();
}
感谢您的时间。
答案 0 :(得分:0)
让我们非常缓慢地浏览代码的相关部分:
dup = runner->next;
这是您稍后delete
的内容。这是重复节点,确定。
runner->next = runner->next->next;
为了便于阅读,如果您将上述行更改为&#34; runner-&gt; next = dup-&gt; next;&#34 ;.它清楚地表明您正在重新关联dup
的前任&#34;围绕它&#34;,将其指向dup
之后的下一个节点。
runner->next->prev = runner->next->prev->prev; //trying to connect to previous node. Works without this line.
好的,runner->next
现在是dup
之后的节点。现在,停下片刻,喝杯咖啡,问自己以下问题:
在双向链表中,假设节点ptr
不是列表中的最后一个节点,应该是什么:
ptr->next->prev
永远是????
嗯,ptr
是列表中的一个节点。 ptr
- &gt;接下来是下一个节点。您希望找到什么作为下一个节点的prev
值?
如果你向前迈出一步,然后退后一步,你会在哪里结束?那么,在这个宇宙中,你将完全结束你开始的地方(忽略相对论的影响)。因此,在经典的双向链表中,ptr->next->prev
将为ptr
,假设ptr
不是列表中的最后一个节点(注意这一部分,它将变得很重要)
所以,我会疯狂地猜测,你的代码应该做的是:
runner->next->prev = runner; // Relink to the previous node
但这也不是正确的答案。请记住,我们假设runner
不是双向链表中的最后一个节点。如果是,那么runner->next
显然是NULL
,因为根据定义,runner
是列表中的最后一个节点(您删除了列表中的最后一个节点,因此{{1} <}是列表中新的最后一个节点),因此这里将发生空指针解除引用。
那么,如果runner
确实是列表中的最后一个节点,您认为应该在这里发生什么?如果你说&#34;没什么&#34;,你有正确的答案:
runner
答案 1 :(得分:0)
dup = runner->next;
runner->next = runner->next->next;
runner->next->prev = runner->next->prev->prev;
1)在我指出的代码块中的第二行之后,当链表的最后一个元素是要删除的元素时,runner->next
变为NULL。因此下一行runner->next->prev
将崩溃,因为它等同于'NULL->next'
。
所以你必须在第2行和第3行之间添加if (runner->next != NULL )
。那就是你说“仅当下一个存在时才连接下一个(仅当不是最后一个项目时)
2)学习调试工具。
答案 2 :(得分:0)
dup = runner->next;
runner->next = dup->next;
if ( dup->next != NULL )
dup->next->prev = runner;
else
back = runner; /* since we are deleting last element */
delete dup;
这可能是一个更清晰的实现,取代:
dup = runner->next;
runner->next = runner->next->next;
runner->next->prev = runner->next->prev->prev; //trying to connect to previous node. Works without this line.
delete dup;