从双向链表中删除重复项时附加指针

时间:2016-01-30 01:20:36

标签: c++ pointers linked-list

我正在实现一个从未排序的双向链表中删除重复项的函数。我删除了其他功能,以保持代码简短和清晰。请假设其他函数(如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();
}

感谢您的时间。

3 个答案:

答案 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;