Pointers 为什么遍历列表是线性时间?

Pointers 为什么遍历列表是线性时间?,pointers,linked-list,time-complexity,Pointers,Linked List,Time Complexity,每个人都知道长度为n的列表可以在O(n)时间内遍历。这是因为从列表的一个元素到下一个元素的每个步骤都假定在O(1)时间内完成。如果我知道我需要存储的最长列表的长度最多为4,那么如果可以的话,我会安排将每个元素存储在一个寄存器中,其中有一个2位地址00、01、10或11。然后,读取正确的地址并到达那里的任务只需要知道几个位。 然而,我一直在想,如果一个列表的长度大约为2^100,那么指针的使用就会减慢。似乎要区分列表中两个不同元素的寄存器,处理器首先必须消化100位地址信息,然后才能知道下一步要处

每个人都知道长度为n的列表可以在O(n)时间内遍历。这是因为从列表的一个元素到下一个元素的每个步骤都假定在O(1)时间内完成。如果我知道我需要存储的最长列表的长度最多为4,那么如果可以的话,我会安排将每个元素存储在一个寄存器中,其中有一个2位地址00、01、10或11。然后,读取正确的地址并到达那里的任务只需要知道几个位。
然而,我一直在想,如果一个列表的长度大约为2^100,那么指针的使用就会减慢。似乎要区分列表中两个不同元素的寄存器,处理器首先必须消化100位地址信息,然后才能知道下一步要处理哪个寄存器。这将使每个步骤的时间需求更像θ(logn),而完整的遍历需要O(nlog(n))的时间需求。

你完全正确。如果有人说遍历一个列表是O(n),那么它是基于这样一个假设,即可以在恒定的时间内从一个元素到下一个元素。如果你改变这些假设,你可能会得到不同的时间复杂度

当人们陈述算法的时间复杂度并用它来讨论在真实计算机上的执行时,以下事实通常被掩盖了:

在真实的物理计算机上,不同的可能输入的数量总是有限的,因此计算机实际上是一个有限状态机(而不是图灵机),严格来说,每个算法的复杂性都是O(1)(可能有一个相当大的常数因子!)。但我们推断出这个有限状态机的行为,就好像它不是有限的一样


在您的示例中,列表遍历算法的有限个可能输入(实际上)受CPU的字长(例如64位)限制,并且不能有长度为2^100的列表(使用通常的基于指针的算法)。严格来说,在64位CPU上遍历列表的复杂度是O(1),但在可能的输入范围内,它的行为类似于O(n)。对于超出该范围的输入,外推将失效。在真正的物理计算机上运行的所有算法都是如此。

您混淆了不同的术语。
n
指列表中的元素数。 从一个元素到下一个元素的移动时间通常被认为是O(1)。 非平凡地址解析的示例对总体复杂度没有影响,只要地址解析以常量为界。因此,即使列表中有2100个元素,并且CPU必须执行几个额外的操作来检索下一个元素,仍然需要O(1)才能到达它,只需要稍微大一点的常量。只有当检索在某种程度上依赖于列表中元素的总数时,复杂性才会受到影响,这将是一个非常尴尬的场景。有可能,但很尴尬。例如,考虑下一个元素地址不是由下一个指针给出的,而是在某个内存位置加密的,为了检索它,需要应用解密算法<代码> k>代码>时间,当代码> k>代码>是当前元素的列表长度时。在本例中,单跳的价格实际上取决于列表长度,并且总的复杂性将增加


注意:这里的假设是物理计算机没有内存限制(否则,谈论复杂性就毫无意义,因为所有算法都需要O(1)个时间)

在这种计算中,通常隐含的假设是,访问任意内存地址等操作都是O(1)。换句话说,如果你使用的是长度为2^100的列表,那么你是在128位左右的CPU上进行的。但我认为关键是,当我们升级计算机以解决更大的问题时,新计算机上的O(1)比原来计算机上的O(1)大。这与我们通常的图灵机复杂性范式并不完全一致,图灵机范式要求所有可能的输入都必须用完全相同的算法来处理。但从某种意义上说,OP是正确的:如果你假设你的计算机没有内存限制,那么假设跟随指针的是O(1)是不合理的——相反,它将是O(log N)。因此,基本假设是计算机内存有限,字长有限,比如64位。问题是,在这种情况下,您不能使用2^100的基于指针的列表。如果您在支持列表长度>2^64的64位计算机上实现列表遍历(而不是使用简单的指针),正如OP正确指出的那样,您确实不能比O(N logN)做得更好。@MoB.您为什么说指针后面是O(logN)?OP使用2^100作为计算机无法直接访问的地址(我假设他引用的是32/64位体系结构).我同意内存是无限的,但问题似乎不是这样说的(2^100不是无限的,即使它不是64位arch直接寻址的)。我的意思是,在一个无限长的地址(不是通常意义上的“指针”)后面是O(logn)其中N是地址,因为您至少需要解析地址。因此,即使在64位计算机上,您也可以使用O(N log N)中(实际上)无限长的列表来实现列表遍历,假设列表存储在具有随机访问功能的设备上(例如,硬盘系统)当然,如果我们假设列表总是可以连续存储,我们可以用O(N)来实现。这完全取决于您的假设。@MoB。这正是我要说的-只有在内存不受限制的情况下,复杂性才会增加,因此需要额外的依赖于n的计算来访问地址。架构在这里不起作用-即使地址超出arch支持范围,如果它受到限制,仍然可以在O(1)中访问它.BTW,链表通常采用非连续存储。对于连续存储