为什么我们说链表插入是常数时间



我知道链表插入是常量时间由于指针的简单重排,但这不需要知道你正在做插入的元素吗?

并且访问该元素需要线性搜索。那么为什么我们不先说插入仍然受到线性搜索瓶颈的约束呢?

编辑:我不是在谈论头部或尾部附加,而是在两者之间的任何地方插入。

是的,它需要已经有一个节点,你要插入旁边。

那么为什么我们不首先说插入仍然受到线性搜索瓶颈的约束呢?

因为这并不一定是的情况,如果你能安排一些事情,使你实际上知道插入点(不仅仅是索引,还有节点)

显然你可以"插入"在前面或后面,这似乎有点作弊,它延伸了单词"插入"的意思。但是考虑另一种情况:当您向列表添加时,在某个时刻您记住了一个节点。就是你选择的任何节点,使用任何条件选择你想要的节点。然后,您可以轻松地在该节点之后或之前插入。

这听起来像是一个非常"构造"的情况,因为它是。对于一个更实际的情况,与此非常相似(但不完全相同),您可以查看Dancing Links算法。

为什么我们说链表插入是常数时间?

因为插入操作是常数时间。

注意定位插入的位置并不被认为是insert操作本身的一部分。这将是一个不同的操作,它可能是也可能不是常数时间,例如,如果包含搜索时间,则得到:

  • 插入:Constant
  • 在尾部插入:Constant
  • 插入到当前元素之前,同时迭代1: Constant
  • 插入索引位置:线性

1)假设你正在迭代

相比之下,ArrayList的插入操作是线性时间。如果包含搜索时间,则得到:

  • 插入头:线性
  • 尾部插入:常数(平摊)
  • 插入到当前元素之前,同时迭代1: 线性
  • 插入索引位置:线性

以下两个操作不同:

  • 操作A:插入链表

  • 操作B:在链表中的特定位置插入

操作A可以在O(1)中实现。新元素可以插入head(或tail,如果维护和需要)。

操作B包括查找,然后插入。查找部分是O(n)。插入方法如上所述,即O(1)。但是,如果将查找结果作为输入提供,例如,如果有像

这样的api
Node * Find(Node * head, int find_property);
Node * InsertAfter(Node * head, Node * existing_node, Node * new_node);

则操作的插入部分为O(1)

最新更新