O(n)具有O(1 / epsilon)空间的重击者?

时间:2016-06-16 06:26:30

标签: algorithm streaming-algorithm bigdata

我知道以下针对重击手的算法:

Algorithm findHeavyHitters(epsilon, inputStream)
    integer k = ceiling(1 / epsilon) - 1
    initialize hashmap H of size k

    while an item i from the input stream arrives:
        if H[i] exists
            increment the value associated with H[i]
        elsif number of items in H < k
            put H[i] into map with value of 1
        elseif there exists an entry j with a value of 0
            remove j and put H[i] into map with value of 1
        else
            decrement all values in H by 1
    endwhile

    return H

如果我错了,请纠正我,但此算法不能在O(n)中运行。是否可以修改此算法,使其在O(n)中运行,同时保持O(1 / epsilon)空间的使用?

对于数据流,算法的要点是返回顶部epsilon * t项。 Epsilon以百分比形式给出(例如,输入0.1表示至少发生10%的数据)。

1 个答案:

答案 0 :(得分:1)

算法以平均时间O(n)运行,因为哈希查找平均为O(1)。

有两个实现细节。首先,最后一步似乎涉及触及H中的每个值:

  • 将H中的所有值减1(

为了生成这个O(1),我们添加了一个额外的存储位置,称为base,它被初始化为0.然后我们按如下方式修改算法:

while an item i from the input stream arrives:
    if H[i] exists
        increment the value associated with H[i]
    elsif number of items in H < k
        put H[i] into map with value of base + 1
    elseif there exists an entry j with a value of base 
        remove j and put H[i] into map with value of base + 1
    else
        increment base
endwhile

第二个问题是在O(1)中找到值为base(或0)的条目。这可以通过将元素保存在&#34; comb&#34;:双链表的链表中来完成。每个内部链接列表包含具有特定计数的条目。外链表按计数顺序包含计数列表,头指向具有最小计数的列表。如果您绘制此数据结构,它看起来像梳子:

[  base    ] -> entry a -> entry b -> entry c
    |
[ base + i ] -> entry d
    |
[ base + j ] -> entry e -> entry f
    |
   etc.

哈希表现在指向条目,而不是包含它们。要增加单个条目的计数,该条目将从其列表中删除(如果列表包含多个元素),并将其插入到下一个列表中或放入单个元素列表中,该列表将在列表之后插入,取决于与下一个列表相关的计数。此操作为O(1)。

梳状数据结构仍为O(k),其中k是散列中元素的数量,因为不能有比元素更多的不同计数。

您可以使用简单数组和每个计数的第一个条目的索引列表,而不是双向链接列表。要将条目移动到下一个计数存储桶,首先将其与具有该计数的最后一个条目交换,然后提前下一个计数列表的开头或插入新的计数列表条目,具体取决于下一个计数列表是否为&#39 ; s计数大于或大于1。要完成交换,有必要更新散列中两个交换条目的位置,但这仍然是O(1)。