【问题标题】:Algorithm to find duplicates in multiple linked lists在多个链表中查找重复项的算法
【发布时间】:2011-08-22 00:35:41
【问题描述】:

在多个(大型)链表中查找重复项的最快方法是什么。 我将尝试用数组来说明这个问题,而不是让它更具可读性。 (为了简单起见,我使用了 0-9 的数字而不是指针)。

list1[] = {1,2,3,4,5,6,7,8,9,0};
list2[] = {0,2,3,4,5,6,7,8,9,1};
list3[] = {4,5,6,7,8,9,0,1,2,3};
list4[] = {8,2,5};
list5[] = {1,1,2,2,3,3,4,4,5,5};

如果我现在问:“列表 1-5 中是否存在数字 8?”我可以对列表进行排序,删除重复项,对所有列表重复此操作并将它们合并到“超级列表”中,然后查看(新)重复项的数量是否等于我搜索的列表数量。假设我得到了正确数量的重复项,我可以假设我搜索的 (8) 存在于所有列表中。 如果我改为搜索 1,我只会得到四个重复项——因此在所有列表中都找不到。

是否有更快/更智能/更好的方法来实现上述目标,而无需以任何方式排序和/或更改列表?

P.S.:问这个问题主要是出于好奇,没有别的! :)

【问题讨论】:

  • 为什么不遍历所有列表并搜索 8 而不是排序/删除重复的故事?
  • @Klark 我认为他知道任何一个查询的成本都是 O(n),使用这种简单的算法,并希望在多个查询中分摊成本。 @Waxhead 我认为您最好通过将数据放在树、哈希表或计数布隆过滤器中来重新表示数据。

标签: algorithm optimization linked-list


【解决方案1】:

只需将每个数字放入哈希表中,并将该项目的出现次数存储在表中即可。当你找到另一个时,只需增加计数器。 O(n) 算法(所有列表中的 n 项)。

如果您想存储每个出现的列表,那么您还需要在每个项目下存储一个集合表示。你可以使用任何集合表示——位向量、列表、数组等。这将告诉你该项目所属的列表。这不会从 O(n) 改变它,只是将工作增加了一个常数因子。

【讨论】:

    【解决方案2】:

    这个问题有点模糊,所以答案取决于你想要什么。

    哈希表是询问有关重复的一般性问题的正确答案,因为它允许您只浏览每个列表一次以构建一个可以回答大多数问题的表;但是,有些问题不需要回答。

    似乎可以回答您的问题的可能案例:

    您是否只需要知道每个列表中是否存在某个值? - 检查第一个列表,直到找到值。如果没有,你就完成了:它不是。对每个连续的列表重复。如果搜索了所有列表并找到了值,则在每个列表中重复该值。在这个算法中,不需要查看每个列表中的每个值,甚至是每个列表,所以这是最快的。

    您是否需要知道是否存在任何重复项? - 如果以数字为键的哈希表中的任何值的计数大于 0,则存在重复...如果您只需要知道这些,您可以直接退出。

    你需要重复的数量吗 在每个表中,分别? - 将每个值乘以列表的数量并添加正在处理的列表的数量。将其存储为哈希键并计算重复项。处理完所有列表后,您就有了一张可以回答各种问题的表格。要检查特定值的重复项,请将其乘以列表计数并检查顺序哈希键。如果每个列表都有一个,则该数字存在于每个列表中。如果该范围内的所有计数都大于 1,则该数字在每个列表中重复。

    等等

    【讨论】:

      【解决方案3】:

      定义一个数组hash并将所有位置值设置为0

      define hash[MAX_SYMBOLS] = {0};
      define new_list[LENGTH]
      defile list[LENGTH] and populate
      

      现在对于list 中的每个元素,使用此数字作为hash 中的索引,并增加hash 的位置。该数字的每次存在都会增加该hash 位置的值一次。所以重复值i 将有hash[i] > 1

      for i=0 to (n - 1)
        do
          increment hash[list[i]]
      endfor
      

      如果您想删除重复项并创建一个新列表,请扫描hash 数组和i 的每个存在,即。如果hash[i] > 0 按照它们在原始列表中出现的顺序将它们加载到新列表中。

      define j = 0
      for i=0 to (n - 1)
        do
          if hash[list[i]] is not 0
            then
              new_list[j] := i
              increment j
          endif
      endfor
      

      请注意,当使用负数时,您将无法直接使用这些值来索引。要使用负数,首先我们可以找到负数的最大量级,并在我们使用它们来索引hash 数组时,使用该量级将所有数字相加。

      find the highest magnitude of negative value into min_neg
      
      for i=0 to (n - 1)
        do
          increment hash[list[i + min_neg]]
      endfor
      

      或者在实现中你可以分配连续的内存,然后在分配的内存块的中间定义一个指针,这样你就可以前后移动,这样你就可以使用负索引。你需要确保你有足够的内存在指针的前后使用。

      int *hash = malloc (sizeof (int) * SYMBOLS)
      int *hash_ptr = hash + (int)(SYMBOLS/2)
      

      现在你可以用-SYMBOLS/2 < i < SUMBOLS/2 + 1hash_ptr[-6] 或一些hash_ptr[i]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-13
        • 2018-03-11
        • 2015-12-01
        • 1970-01-01
        • 2018-05-12
        相关资源
        最近更新 更多