【问题标题】:How to remove duplicate entries in a linked list input?如何删除链表输入中的重复条目?
【发布时间】:2021-01-12 23:08:09
【问题描述】:

我的任务是删除链接列表中的所有重复条目。假设列表是从最小到最大排序的,因此我需要做的就是删除彼此相邻的重复项。

例如:如果列表在调用 remove_duplicates() 之前包含 {1,2,2,2,3,3,4,5,5,5,5,5,6},它应该包含 {1,2 ,3,4,5,6} 之后。

我的问题是,每当调用 remove_duplicates() 时,我的代码也会打印重复项。 这是我的代码:

list.cpp:

#include <iostream>
using namespace std;
#include "list.h"

// on some machines member variables are not automatically initialized to 0
List::List()
{
    m_head = NULL;
    m_length = 0;
}

// delete all Nodes in the list
// since they are dynamically allocated using new, they won't go away
// automatically when the list is deleted
// Rule of thumb: destructor deletes all memory created by member functions
List::~List()
{
    while (m_head)
    {
        Node *tmp = m_head;
        m_head = m_head->m_next;
        delete tmp;
    }
}

// always insert at the front of the list
// Note: this works even in the SPECIAL CASE that the list is empty
void List::insert(int value)
{
    if (!m_head || value < m_head->m_value)
    {
      m_head = new Node(value, m_head);
    }
    else
    {
      Node *ptr = m_head;
      while (ptr->m_next != NULL && value > ptr->m_next->m_value)
      {
        ptr = ptr->m_next;
      }
      ptr->m_next = new Node(value, ptr->m_next);
    }
    m_length++;
}

// iterate through all the Nodes in the list and print each Node
void List::print()
{
    for (Node *ptr = m_head; ptr; ptr = ptr->m_next)
    {
        cout << ptr->m_value << endl;
    }
}

void List::remove_duplicates()
{
    Node *curr = m_head;
    Node *temp = m_head;
    Node *delPtr = NULL;

    if(curr == NULL)
    {
        return;
    }

    if(curr != NULL)
    {

        if(curr -> m_value == curr ->m_next ->m_value)
       {
           delPtr = curr;
           curr = curr -> m_next;
           temp ->m_next = curr;
           delete delPtr;
       }

       else
       {
           curr = curr -> m_next;
       }

    }

    }

list.h:

class List
{
    public:
        List();
        ~List();

        void insert(int value); // insert at beginning of list
        void print(); // print all values in the list
        int length() {return m_length;}
        void remove_duplicates();
        int *convert_to_array(int &size);

    private:
        class Node
        {
            public:
                Node(int value, Node *next)
                {m_value = value; m_next = next;}
                int m_value;
                Node *m_next;
        };
        Node *m_head;
        int m_length;
};

main.cpp:

#include <assert.h>
#include <iostream>
using namespace std;
#include "list.h"

int main()
{
    List list;
    int value;

    // read values and insert them into list
    while (cin >> value)
    {
      list.insert(value);
    }


    cout << "printing original list: \n";
    list.print();

    list.remove_duplicates();
    cout << "printing list after removing duplicates: \n";
    list.print();
}

注意:我的导师已经给了我一切,我应该写的唯一代码是void List::remove_duplicates()

我在 stackoverflow 上查找了其他示例,但似乎没有一个可以帮助我解决我的情况。 另外,我想提一下,我对链接列表以及它们的功能仍然很陌生。因此,我不确定从这里去哪里。任何帮助将不胜感激

【问题讨论】:

  • 有什么理由不使用std::list 吗?使用 sortunique 您可以删除重复项。
  • 我在 stackoverflow 上查找了其他示例,但似乎没有一个对我的情况有帮助。 -- 老实说,你不会学习如何弄清楚通过首先查看代码示例来了解链表的复杂性。您应该做的第一件事是在纸上绘制一个链表结构,其中指针是线,链接是框。然后制定在纸上如何删除重复项,然后将您在纸上的内容写入代码。 '
  • 您能解释一下您的 remove_duplicates 应该如何删除多个重复项吗?
  • @PaulMcKenzie 我认为我写下的内容很有道理,但我会先尝试将其写在纸上。
  • 这是另一个想法。假设它不是一个链表,而是一个可调整大小的数组(如std::vector)。您将如何在循环中删除重复项?假设您有两个索引(就像您有两个链接,curr 和 curr->next)。还假设有一个“擦除”功能可以擦除某个索引处的项目。确保索引不会弄乱或您不会错过任何重复项会涉及什么逻辑?不管这个逻辑是什么,对于链表来说都是一样的逻辑,只是你处理的是 curr 和 curr->next,而不是索引 ii+1

标签: c++ class linked-list nodes


【解决方案1】:

您需要同时使用当前指针的地址 和当前指针来遍历您的列表。见Linus on Understanding Pointers。由于您不仅要删除具有特定值的节点,而且要在列表中向前扫描删除具有该值的所有节点,因此您希望遍历每个节点,并在循环中向前扫描删除所有节点与当前节点的值。

您可以通过检查m_next-&gt;m_value 来做到这一点,如果它与当前节点值相同,则将当前指针 ADDRESS 处的节点替换为下一个节点内容。由于您仍然有一个指向已替换节点的指针,您可以简单地 delete 该节点,然后从当前节点的地址更新指针。

这假定您的列表按您在问题中显示的排序顺序排列。如果不是,您将需要多次扫描列表。如图所示的排序顺序,您可以这样做:

/* list must be in sort order */
void List::remove_duplicates()
{
    Node **pp = &m_head,    /* current address of head (pointer-to-pointer) */
          *p = m_head;      /* pointer to head */
    
    /* loop over each node */
    for (; p; pp = &p->m_next, p = p->m_next) {
        /* while m_next and current value == next value */
        while (p->m_next && (*pp)->m_value == p->m_next->m_value)
        {
            *pp = p->m_next;    /* set node at current address to next node */
            delete p;           /* delete original node at that address */
            p = *pp;            /* update pointer to current node address */
        }
    } 
}

(如果当前节点和下一个节点具有相同的m_value,则您将丢弃当前节点(并正确删除内存)并用下一个节点替换它)

例如,如果您的列表最初包含:

 0 0 1 1 1 2 3 4 4 5 6 6 6 7 8 9 9 9

调用list.remove_duplicates() 会导致:

 0 1 2 3 4 5 6 7 8 9

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

  • 当然,很高兴为您提供帮助。使用指针地址和指针在列表中工作需要时间来消化。但这无需担心prevcurrentnext。如果您需要更改那里的内容,您只需使用指针的地址并将其他内容放在该地址。对于列表插入和删除,它的工作方式相同。祝你编码顺利。
猜你喜欢
  • 1970-01-01
  • 2013-03-09
  • 2012-04-10
  • 2010-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
  • 2015-01-04
相关资源
最近更新 更多