Algorithm 二次探测:在现实生活中的哪个场景是O(n)复杂度

Algorithm 二次探测:在现实生活中的哪个场景是O(n)复杂度,algorithm,data-structures,time-complexity,big-o,Algorithm,Data Structures,Time Complexity,Big O,我正在学习数据结构和算法。我学到的hashmap几乎所有的操作都是O(1)。这是一种执行二次探测分辨率的方法,它返回所需对象的位置 private int findPos( Object x ) { int offset = 1; int currentPos = myhash( x ); //Using quadratic probing while( array[ currentPos ] != null && !a

我正在学习数据结构和算法。我学到的hashmap几乎所有的操作都是O(1)。这是一种执行二次探测分辨率的方法,它返回所需对象的位置

private int findPos( Object x )
{
    int offset = 1;
    int currentPos = myhash( x ); //Using quadratic probing 
    
    while( array[ currentPos ] != null &&
            !array[ currentPos ].element.equals( x ) )
    {
        currentPos += offset;  // Compute ith probe
        offset += 2;
        if( currentPos >= array.length )
            currentPos -= array.length;
    }
    
    return currentPos;
}
我在做作业,我必须找出这个方法的复杂性。这是一个场景:

数组表示一个英语词典,其中每个元素都是其中的一个单词。这个家庭作业的答案是O(1)复杂性。但是我想知道为什么O(n)复杂性不是,因为里面有很多元素(大约171476个单词),这会导致很多冲突。换句话说,从这个场景中,我如何确定这个方法始终是O(1)

编辑 我作业中的问题是:在最坏的情况下,这种方法的复杂性是什么。还是O(1)?

非最坏情况。。。。它是O(1)而不是O(n),因为搜索时间不取决于数组的大小。是的,您将获得更多元素的冲突,但平均每个搜索不会有更多的冲突,因为数组的大小随着n的增加而增加

编辑:由于问题规定数据是来自英语的单词,因此对n的最大可能大小有一个限制,这意味着您实际上可以保证哈希函数不会发生冲突,即使在最坏的情况下也会得到O(1)的答案

在更糟糕的情况下,这种方法的复杂性是什么。即使情况更糟,它仍然是O(1)吗

要回答你的问题,你真的必须定义你所说的最坏情况是什么意思。哈希表的实现非常依赖于两个因素:要存储在哈希表中的数据的(概率)分布,以及定义的哈希函数。知道了这两个因素,你就可以做一个普通的案例分析。如果没有这两条信息,您可以假设最坏的情况,例如:

  • 您将始终获得相同的存储值,例如数字“1”
  • 你的散列函数是f(x)=x
在这种情况下,如果您对bucket使用链表,那么最坏的情况确实是O(n)

但是,如果您有更多的信息,例如数据遵循统一的分布,并且您使用了合理的哈希函数,那么您可以在平均情况下显示大多数操作应该是O(1)。在上一句中,描述符“平均值”是通过对数据所遵循的概率分布进行平均来精确定义的


我不清楚您需要的分析有多详细,但通常对于开放寻址(不管是哪种),平均运行时间的分析如下

a=n/n
作为哈希表的加载因子,其中
n
是存储的元素数,
n
是存储桶数。假设没有集群问题(由于数据或哈希函数),并且所有探测的可能性相同(证明二次探测是分开的),那么您可以断言

P(probe hits occupied bucket) = a
P(probe hits unoccupied bucket) = 1-a
P(probe hits unoccupied bucket in 2 steps) = a (1-a)
P(probe hits unoccupied bucket in k steps) = a^{k-1} (1-a)
因此,探测的平均运行时间为

E(number of steps in probe) = \sum {for k = 0 to m} k a^{k-1}(1-a)
                            <=\sum {for k = 0 to infty} k a^{k-1}(1-a)
                            = (1-a) / (1-a)^2
                            = 1 / (1 - a)
因此
E(探针中的步数)
为O(1)

整个分析的关键在于能够认识到无穷和有一个很好的收敛的闭合形式

综上所述,我给出的上述证明在一般情况下成立,但需要在您使用的探测技术上满足以下条件(可能需要单独证明):

  • 探测技术根据撞击未占用/占用铲斗的负载系数得出统一的概率(即
    P(探测撞击占用铲斗)=a
  • 探测技术以有限的步骤结束

根据分析的详细程度,您可能必须证明二次探测的这两个属性才能完成证明。(请注意,只有当荷载系数为a<.5时,二次探测才能保证终止)

对于每个元件,有两种情况:要么发生碰撞,要么不发生碰撞。考虑两种情况的概率来计算每个元素插入的估计复杂度。最后,取
n
值的平均值,找出平均插入时间。哈希表上的大多数操作不是O(1),而是O(n)或更糟。它们的预期运行时间为O(1)。“内部有大量元素(约171476个单词),这将导致大量冲突”-冲突的可能性不取决于元素的数量,而是取决于负载系数。只要底层数组有足够的空间容纳元素,那么灾难性冲突(即一系列导致O(n)行为的冲突)就极不可能发生。@ldog因此,正如您所说,它们是O(1)预期时间,而不是O(1)最坏情况时间。就像快速排序一样,O(n logn)是预期时间,但O(n^2)是最坏情况时间。除非我们另有说明,否则没有默认假设我们正在测量最坏的情况。使用二次探测的hashMap最坏的情况仍然是O(1)吗?我已经更新了我的答案,以反映在最坏的情况下它可能是O(1)。因此,为了澄清我的示例,数组上使用的数据是字典中的单词。答案是O(1)(我的家庭作业)吗?因为我的数据(字典中的单词)的分布是均匀的?关于使用的哈希函数有更多的信息吗?它会对性能分析产生很大影响。它使用Java中的hashCode()方法,使用Horner算法,我想这是一个很好的哈希函数好的,我已经更新了答案,以反映到目前为止您给出的所有信息。根据您实际需要显示YMMV的内容,但我至少概述了常量运行时间的典型证明的框架。因此,因为我使用0.5的二次探测,它解决了“产生统一概率”和“终止于有限步数”的问题。所以
E(number of steps in probe) <= 1 / (1-.5) = 2