了解从链表中删除重复项的复杂性

Posted

技术标签:

【中文标题】了解从链表中删除重复项的复杂性【英文标题】:Understanding complexity of deleting duplicates from a linked-list 【发布时间】:2017-05-25 17:23:10 【问题描述】:

我编写了这个程序来从一个未排序的链表中删除重复的节点:

#include<bits/stdc++.h>
using namespace std;

/* A linked list node */
struct Node

    int data;
    struct Node *next;
;

// Utility function to create a new Node
struct Node *newNode(int data)

   Node *temp = new Node;
   temp->data = data;
   temp->next = NULL;
   return temp;


/* Function to remove duplicates from a
   unsorted linked list */
void removeDuplicates(struct Node *start)

    // Hash to store seen values
    unordered_set<int> seen;

    /* Pick elements one by one */
    struct Node *curr = start;
    struct Node *prev = NULL;
    while (curr != NULL)
    
        // If current value is seen before
        if (seen.find(curr->data) != seen.end())
        
           prev->next = curr->next;
           delete (curr);
        
        else
        
           seen.insert(curr->data);
           prev = curr;
        
        curr = prev->next;
    


/* Function to print nodes in a given linked list */
void printList(struct Node *node)

    while (node != NULL)
    
        printf("%d ", node->data);
        node = node->next;
    


/* Driver program to test above function */
int main()

    /* The constructed linked list is:
     10->12->11->11->12->11->10*/
    struct Node *start = newNode(10);
    start->next = newNode(12);
    start->next->next = newNode(11);
    start->next->next->next = newNode(11);
    start->next->next->next->next = newNode(12);
    start->next->next->next->next->next =
                                    newNode(11);
    start->next->next->next->next->next->next =
                                    newNode(10);

    printf("Linked list before removing duplicates : \n");
    printList(start);

    removeDuplicates(start);

    printf("\nLinked list after removing duplicates : \n");
    printList(start);

    return 0;

在哈希表中查找每个元素会影响复杂性吗?如果是,考虑到该集合是作为二叉搜索树实现的,其中在最坏情况下搜索元素的成本为 O(logn),该算法的时间复杂度应该是多少。 据我说 T(n)=T(n-1)+log(n-1) 即。第 n 个元素将执行 log(n-1) 比较(即具有 n-1 个元素的树的高度) 请给出数学分析。

【问题讨论】:

这取决于你的哈希表是否有很多冲突,通常很少,所以它可能是 O(1),因此不会影响复杂性。 嗯,unordered_set 实际上具有恒定的时间复杂度(平均而言),因此为 O(1)。 您共享的方法尽可能高效,因为您需要遍历列表至少一次 O(N),删除重复项,使用集合或无序集合不会影响整体时间因为这两个将分别是 O(log(N)) 和 O(1) 用于查找。 @AmitKumar 在最坏的情况下,对于 N 个元素,查找的总成本将变为 N*O(logN) 。这肯定会影响复杂性。 【参考方案1】:

在哈希表中查找每个元素会影响复杂度吗?

好吧,在您的代码中,您使用的是 unordered_set,它的平均复杂度为 O(1),所以简单的答案是 - 否。

...考虑到该集合被实现为二叉搜索树,其中搜索元素的成本在最坏情况下为 O(logn)。

同样,您选择了unordered_set,它不是二分搜索。我相信set 的一些实现使用红/黑树,你会看到 O(logN),但对于unordered_set,它应该是恒定的时间。所以现在唯一的问题是你的链表的遍历。其中,由于您在访问每个节点时只是沿一个方向行走,因此是 O(N) 操作。

【讨论】:

如果我使用 set 而不是 unordered_set 会怎样。这将如何影响复杂性? @abhishekgupta - 我已经回答过了。使用std::set,您正在查看 O(logN) 而不是 O(1) 摊销。您仍然需要遍历 O(N) 的列表,并且设置的查找为 O(logN)。

以上是关于了解从链表中删除重复项的复杂性的主要内容,如果未能解决你的问题,请参考以下文章

1.2从链表中移除重复项

从 MySQL 中的大表中删除重复项的最快过程是啥

Leetcode删除链表中的重复元素

Leetcode删除链表中的重复元素

8 数据结构与算法

javascript中的链表结构—从链表中删除元素