单个 link 列表中的时间复杂度
Time Complexity in singly link list
我正在研究数据结构:单link列表。
网站说单linked列表的插入和删除时间复杂度为O(1)
。我错过了什么吗?
我用 C++ 做这个,我只有一个 root pointer
。如果我想在最后插入,那么我必须一直走到后面,也就是O(n)
。
对此的解释是,linked table中的大O符号指的是函数实现本身,不包括遍历列表以查找列表中的前一个引用节点.
如果您按照 link 到 Singly-LinkedList implementation 的维基百科文章,它会变得更清楚:
function insertAfter(Node node, Node newNode)
function removeAfter(Node node)
以上函数签名已经将前导节点作为参数(隐含地与其他变体相同)。
寻找前驱是一个不同的操作,可能是 O(n) 或其他时间复杂度。
您在两个地方错过了界面:
std::list::insert()/std:list::erase() 需要一个指向要插入或擦除的元素的迭代器。这意味着您没有搜索,而只是更改列表中元素中的两个指针,这是恒定的复杂性。
可以通过 push_back 在列表末尾插入。该标准要求这也是 O(1)。这意味着,如果您有 std::list,它将存储第一个和最后一个元素。
编辑:抱歉,您遇到了 std::forward_list。即使名称为 insert_after 和 erase_after,第 1 点也适用于此。点2不行,你要迭代到列表末尾。
I do this in C++, and I only have a root pointer. If I want to insert at the end, then I have to travel all the way to the back, which means O(n).
这是两个操作,您首先 搜索 O(n) 给定位置的列表,然后 将 O(1) 元素插入列表。
在单链表中,插入操作包括:
前一个元素的交替指针
将对象包装到数据结构中并将其指针设置为下一个元素
两者都不受列表大小的影响。
另一方面,以堆结构为例。每个元素的插入都需要 O(log(n)) 操作才能保留其结构。树结构具有类似的机制,在插入时将 运行 并取决于当前树的大小。
这里认为你已经有了节点,之后你需要添加一个新的元素
在这种情况下,单链表的插入时间复杂度变为 O(1)。
事实是,与 array
不同,我们不需要在插入时移动 singly-linked list
的元素。因此,一个singly-linked列表的插入时间复杂度是O(1)
.
假设您有一个 Python list
填充整数...
my_list = [9, 8, 4, 5, 6]
... 并且您想在元素 8
之后插入数字 3
。
my_list.insert(2, 3)
打印结果为:
[9, 8, 3, 4, 5, 6]
当你对my_list
进行插入时,元素3
之后的其他元素都向右移动,因此它们的索引也发生了变化。因此,在给定索引处插入元素的时间复杂度为 O(n)
.
但是singly-linked lists
里面没有数组元素,但是chained nodes
和node values
.
Image source: LeetCode
如上图所示,next
节点的prev
节点holds the reference
。正如@πìντα ῥεῖ 所说,“函数签名已经将前导节点作为参数”。你可以在O(n)
时间找到前一个节点,但是在插入一个新节点时,你只需要改变连接节点的地址,即O(1)
时间复杂度。
我正在研究数据结构:单link列表。
网站说单linked列表的插入和删除时间复杂度为O(1)
。我错过了什么吗?
我用 C++ 做这个,我只有一个 root pointer
。如果我想在最后插入,那么我必须一直走到后面,也就是O(n)
。
对此的解释是,linked table中的大O符号指的是函数实现本身,不包括遍历列表以查找列表中的前一个引用节点.
如果您按照 link 到 Singly-LinkedList implementation 的维基百科文章,它会变得更清楚:
function insertAfter(Node node, Node newNode) function removeAfter(Node node)
以上函数签名已经将前导节点作为参数(隐含地与其他变体相同)。
寻找前驱是一个不同的操作,可能是 O(n) 或其他时间复杂度。
您在两个地方错过了界面:
std::list::insert()/std:list::erase() 需要一个指向要插入或擦除的元素的迭代器。这意味着您没有搜索,而只是更改列表中元素中的两个指针,这是恒定的复杂性。
可以通过 push_back 在列表末尾插入。该标准要求这也是 O(1)。这意味着,如果您有 std::list,它将存储第一个和最后一个元素。
编辑:抱歉,您遇到了 std::forward_list。即使名称为 insert_after 和 erase_after,第 1 点也适用于此。点2不行,你要迭代到列表末尾。
I do this in C++, and I only have a root pointer. If I want to insert at the end, then I have to travel all the way to the back, which means O(n).
这是两个操作,您首先 搜索 O(n) 给定位置的列表,然后 将 O(1) 元素插入列表。
在单链表中,插入操作包括:
前一个元素的交替指针
将对象包装到数据结构中并将其指针设置为下一个元素
两者都不受列表大小的影响。
另一方面,以堆结构为例。每个元素的插入都需要 O(log(n)) 操作才能保留其结构。树结构具有类似的机制,在插入时将 运行 并取决于当前树的大小。
这里认为你已经有了节点,之后你需要添加一个新的元素
在这种情况下,单链表的插入时间复杂度变为 O(1)。
事实是,与 array
不同,我们不需要在插入时移动 singly-linked list
的元素。因此,一个singly-linked列表的插入时间复杂度是O(1)
.
假设您有一个 Python list
填充整数...
my_list = [9, 8, 4, 5, 6]
... 并且您想在元素 8
之后插入数字 3
。
my_list.insert(2, 3)
打印结果为:
[9, 8, 3, 4, 5, 6]
当你对my_list
进行插入时,元素3
之后的其他元素都向右移动,因此它们的索引也发生了变化。因此,在给定索引处插入元素的时间复杂度为 O(n)
.
但是singly-linked lists
里面没有数组元素,但是chained nodes
和node values
.
Image source: LeetCode
如上图所示,next
节点的prev
节点holds the reference
。正如@πìντα ῥεῖ 所说,“函数签名已经将前导节点作为参数”。你可以在O(n)
时间找到前一个节点,但是在插入一个新节点时,你只需要改变连接节点的地址,即O(1)
时间复杂度。