python有排序列表吗?
Posted
技术标签:
【中文标题】python有排序列表吗?【英文标题】:Does python have a sorted list? 【发布时间】:2010-11-09 17:40:08 【问题描述】:我的意思是一个结构:
x.push()
操作的 O(log n) 复杂度
O(log n) 复杂度找到一个元素
计算 list(x)
的 O(n) 复杂度将被排序
我还有一个关于 list(...).insert(...)
的性能的相关问题,现在是 here。
【问题讨论】:
memcpy
仍然是一个 O(n) 操作。我不确定 Python 如何实现列表确切地,但我敢打赌它们存储在连续的内存中(当然不是作为链表)。如果确实如此,那么您演示的使用bisect
的插入将具有复杂性O(n)。
遗憾的是没有开箱即用。但是 Grant Jenk 的 sortedcontainers 库非常棒。 ***.com/a/22616929/284795
【参考方案1】:
您的 big-O 要求有什么特殊原因吗?或者你只是想让它快点? sortedcontainers 模块是纯 Python 且速度很快(就像在 blist 和 rbtree 等 fast-as-C 实现中一样)。
performance comparison 显示它的基准测试速度更快或与 blist 的排序列表类型相当。另请注意,rbtree、RBTree 和 PyAVL 提供排序的 dict 和 set 类型,但没有排序的列表类型。
如果性能是一项要求,请始终记住进行基准测试。一个使用 Big-O 表示法证明速度快的模块应该被怀疑,直到它也显示基准比较。
免责声明:我是 Python sortedcontainers 模块的作者。
安装:
pip install sortedcontainers
用法:
>>> from sortedcontainers import SortedList
>>> l = SortedList()
>>> l.update([0, 4, 1, 3, 2])
>>> l.index(3)
3
>>> l.add(5)
>>> l[-1]
5
【讨论】:
事实上,我将 sortedcontainers 与 bisect 进行了比较:0.0845024989976
for SortedList.add() vs 0.596589182518
for bisect.insort(),因此速度差异为 7 倍!我预计速度差距会随着列表长度而增加,因为 sortedcontainers 插入排序在 O(log n) 中工作,而 bisect.insort() 在 O(n) 中工作。
@gaborous 因为 bisect 仍然使用列表,所以插入仍然是O(n)
【参考方案2】:
标准的 Python 列表不以任何形式排序。标准的 heapq 模块可用于将 O(log n) 附加到现有列表并删除 O(log n) 中最小的一个,但它不是您定义中的排序列表。
有多种 Python 平衡树实现可以满足您的要求,例如rbtree、RBTree 或 pyavl。
【讨论】:
+1 用于 rbtree,效果很好(但包含本机代码;不是纯 python,可能不太容易部署) sortedcontainers 是纯 Python 和 fast-as-C(如 rbtree)的性能比较。 “在你的定义中不是一个排序列表。”怎么样? heapq 只允许找到最小的元素; OP 要求一种可以在 O(log n) 中找到任何元素的结构,而堆不是。【参考方案3】:虽然我还没有检查过基本 Python 列表操作的“大 O”速度,
在这种情况下,bisect
标准模块可能也值得一提:
import bisect
L = [0, 100]
bisect.insort(L, 50)
bisect.insort(L, 20)
bisect.insort(L, 21)
print L
## [0, 20, 21, 50, 100]
i = bisect.bisect(L, 20)
print L[i-1], L[i]
## 20, 21
PS。啊,对不起,bisect
在引用的问题中提到。不过,我认为如果这里有这些信息不会有太大的伤害)
PPS。还有CPython lists are actually arrays(不是,比如说,skiplists 等)。嗯,我想它们一定很简单,但对我来说,这个名字有点误导。
所以,如果我没记错的话,平分/列表速度可能是:
对于 push():最坏情况的 O(n) ; 对于搜索:如果我们认为数组索引的速度为 O(1),则搜索应该是 O(log(n)) 操作; 对于列表的创建:O(n) 应该是列表复制的速度,否则对于同一个列表是 O(1)更新。在 cmets 讨论之后,让我在这里链接这些 SO 问题:How is Python's List Implemented 和 What is the runtime complexity of python list functions
【讨论】:
push() 应该在 O(log n) 中,因为列表已经排序。 也许我应该说"for an insert op"。无论如何,那是大约一年前的事了,所以现在我可以很容易地混淆或错过一些东西 您总是可以在 O(log n) 中将一个值插入到排序列表中,请参阅二分查找。 push() 被定义为插入操作。 是的。但是,虽然 finding 插入位置确实需要 O(log n) 个操作,但实际插入(即,将元素添加到数据结构中)可能取决于该结构(考虑在排序数组中插入元素)。而作为Python lists are actually arrays,这可能需要 O(n)。由于 cmets 的大小限制,我将从答案的文本中链接两个相关的 SO 问题(见上文)。 很好的论据。我不知道在 Python 中作为数组处理的列表。【参考方案4】:虽然它没有(还)提供自定义搜索功能,但heapq
模块可能会满足您的需求。它使用常规列表实现堆队列。您必须编写自己的有效成员资格测试,利用队列的内部结构(可以在 O(log n) 中完成,我想说...)。有一个缺点:提取排序列表具有复杂性 O(n log n)。
【讨论】:
很好,但很难一分为二。 堆中怎么会有 O(log n) 成员资格测试?如果您正在寻找值 x,如果您发现大于 x 的东西,您可以停止向下查看分支,但是对于 x 的随机值,它有 50% 的可能性位于叶子处,并且您可能无法修剪太多。 【参考方案5】:import bisect
class sortedlist(list):
'''just a list but with an insort (insert into sorted position)'''
def insort(self, x):
bisect.insort(self, x)
【讨论】:
在 bisect.insort() 中隐含的 insert() 是 O(n)【参考方案6】:我会使用biscect
或sortedcontainers
模块。我真的没有经验,但我认为heapq
模块有效。它包含一个Heap Queue
【讨论】:
【参考方案7】:在 Python 上实现您自己的排序列表可能并不难。下面是一个概念证明:
import bisect
class sortlist:
def __init__(self, list):
self.list = list
self.sort()
def sort(self):
l = []
for i in range(len(self.list)):
bisect.insort(l, self.list[i])
self.list = l
self.len = i
def insert(self, value):
bisect.insort(self.list, value)
self.len += 1
def show(self):
print self.list
def search(self,value):
left = bisect.bisect_left(self.list, value)
if abs(self.list[min([left,self.len-1])] - value) >= abs(self.list[left-1] - value):
return self.list[left-1]
else:
return self.list[left]
list = [101, 3, 10, 14, 23, 86, 44, 45, 45, 50, 66, 95, 17, 77, 79, 84, 85, 91, 73]
slist = sortlist(list)
slist.show()
slist.insert(99)
slist.show()
print slist.search(100000000)
print slist.search(0)
print slist.search(56.7)
=========结果============
[3、10、14、17、23、44、45、45、50、66、73、77、79、84、85、86、91、95、101]
[3、10、14、17、23、44、45、45、50、66、73、77、79、84、85、86、91、95、99、101]
101
3
50
【讨论】:
这还是基于insort
,时间复杂度为O(n)。【参考方案8】:
AVL 树 [https://en.wikipedia.org/wiki/AVL_tree] 与中序遍历相结合将在所需的时间复杂度内解决此问题。
【讨论】:
【参考方案9】:有趣的案例:如果您的列表 L
已经排序(例如,因为您按排序顺序附加它们),您可以从 O(log n) 中的快速 查找 中受益使用此方法的标准 Python 列表:
import bisect
def in_sorted_list(elem, sorted_list):
i = bisect.bisect_left(sorted_list, elem)
return i != len(sorted_list) and sorted_list[i] == elem
L = ["aaa", "bcd", "hello", "world", "zzz"]
print(in_sorted_list("hellu", L)) # False
更多详情请见this answer。
【讨论】:
以上是关于python有排序列表吗?的主要内容,如果未能解决你的问题,请参考以下文章