如何设计一个 arraylike 数据结构,支持 O(1) 的按索引访问和 O(1) 的按索引删除.

2021-01-07 21:25:05 +08:00
 littleMaple

用代码来作为例子,假设我们的数据结构名为 MagicArray:

magic_array = MagicArray("How are you", "I am find", "Thank you", "And you")

print(magic_array[2])  # 这一行应该打印 "Thank you",且该行的运行时间应该与 magic_array 的长度无关,或者至少“摊还地”无关.

magic_array.remove(1)  # 这一行的运行时间应该与 magic_array 的长度无关,或者至少“摊还地”无关.

print(magic_array[2])  # 这一行应该打印 "And you",且该行的运行时间应该与 magic_array 的长度无关,或者至少“摊还地”无关.

如果我们无法设计出这样的数据结构,我们如何形式证明它不可能存在?如果确实不可能存在,我们可以设计出的最接近它的最快的数据结构能够有多快?

2122 次点击
所在节点    算法
22 条回复
xupefei
2021-01-07 21:28:06 +08:00
链表+位置到节点的哈希表。
这题算是 leetcode 中等难度。
php8
2021-01-07 21:28:42 +08:00
咱 php 数组插入和删除都是 O(1)滴,还能当 map 用,难怪被公认是最好的语言
xupefei
2021-01-07 21:33:10 +08:00
@xupefei 不过我这个办法删除比 O1 复杂,最坏情况下是 On 。
用 jumplist 可能会更好
littleMaple
2021-01-07 21:33:51 +08:00
@xupefei #1 删除操作的时候维护「位置映射到节点的哈希表」就需要 O(n) 的复杂度吧?例如 magic_array.remove(1) 操作运行的时候,2->"Thank you" 和 3->"And you" 这两个映射就需要更新成 1->"Thank you" 和 2->"And you"。
xupefei
2021-01-07 21:36:17 +08:00
最好的办法应该是用 rope,能做到 logn 复杂度
sunkai0609
2021-01-07 22:06:26 +08:00
php 的数组
sunkai0609
2021-01-07 22:07:54 +08:00
@sunkai0609 请无视我
hanxiV2EX
2021-01-07 22:10:50 +08:00
跳跃表,redis 的 zset

只能做到 lgn
love
2021-01-07 23:18:15 +08:00
这和 map 用整数做 key 有什么区别?
mxT52CRuqR6o5
2021-01-07 23:41:16 +08:00
@php8 我 google 了一下 php 的 array_splice 可并不是 O(1)而是 O(offset+length)啊
mxT52CRuqR6o5
2021-01-07 23:42:31 +08:00
这个问题一两句应该证明不了,书上也许会有答案
raaaaaar
2021-01-07 23:55:06 +08:00
结合链表的增删和数组的查改优点就是跳表,所以不可能存在你说得这种上界都是 O(1) 的。
查找操作最好的就是利用内存的随机存取特点,但是要实现删除操作就必然和随机存取冲突,因为删除节点内存就变了,地址也变了,要不影响随机存取,内存肯定要移动的。
littleMaple
2021-01-08 00:05:26 +08:00
@love #9 因为要求是 arraylike,例如如果删除了第三个元素,第四个元素至最后一个元素对应的索引都要相应的减一.
littleMaple
2021-01-08 00:10:04 +08:00
@raaaaaar #12 确实如此,直观上来说 O(1) access 和 O(1) remove 不可能同时满足,但是若是 amortized O(1) access 和 amortized O(1) remove 呢?放宽一点要求之后不知道能不能同时满足.
php8
2021-01-08 00:50:39 +08:00
@mxT52CRuqR6o5 是我理解有误,没有考虑到删除之后下标要依次挪一格
wangxiyu191
2021-01-08 01:51:39 +08:00
没要求插入的时间和空间复杂度,钻个空子。可以在初始化 /插入时就生成好一次或多次删除后可能达到的所有的状态。这样插入和删除就都能做 O(1) 了。
wangxiyu191
2021-01-08 01:53:12 +08:00
@wangxiyu191 上面最后一句打错。“这样插入和删除就都能做 O(1) 了” -》 “这样查询和删除就都能做 O(1) 了”
sunnybird
2021-01-08 02:14:16 +08:00
算法核心思想,空间换时间
shiji
2021-01-08 02:42:37 +08:00
@littleMaple Hashmap 的核心不就是 array 么。 又没有必要说 array 不能留空,必须一字排开
littleMaple
2021-01-08 03:02:04 +08:00
@wangxiyu191 #16 你居然能想到这样暴力的方案 XD 而且居然是对的.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/742693

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX