Pythonにはソートされたリストがありますか?


128

それによって私は次のような構造を意味します:

  • 以下のためのO(Nログ)複雑x.push()操作
  • 要素を見つけるためのO(log n)複雑さ
  • list(x)ソートするO(n)の計算量

パフォーマンスについても関連する質問がlist(...).insert(...)ありました


memcpyまだO(n)操作です。Pythonがリストをどのように正確に実装するかはわかりませんが、リストが連続したメモリに(確かにリンクリストとしてではなく)保存されているのではないかと思います。それが本当にそうである場合、bisectあなたがデモンストレーションを使用する挿入は複雑さO(n)を持ちます。
Stephan202 2009

2
悲しいことに箱から出していない。しかし、Grant Jenksortedcontainersライブラリは優れています。stackoverflow.com/a/22616929/284795
大佐パニック

回答:


52

標準のPythonリストは、どのような形式でもソートされていません。標準のheapqモジュールを使用して、O(log n)を既存のリストに追加し、O(log n)の最小のものを削除できますが、定義ではソートされたリストではありません。

例えば、あなたの要件を満たすためのPythonのためのバランスの木の様々な実装がありrbtreeRBTree、またはpyavlが


1
rbtreeのために、それは非常によく1を動作します(ただし、ネイティブコードが含まれています。おそらく、導入が容易ではないではない、純粋なのpython、)
ウィル

12
Sortedcontainersは、パフォーマンスを比較した、純粋なPythonとCとしての高速(rbtreeのような)です。
GrantJ 2014年

「あなたの定義ではソートされたリストではありません。」どうして?
大佐パニック

4
heapqは最小の要素のみを見つけることができます。OPはO(log n)内の任意の要素を見つけることができる構造を求めていましたが、ヒープはそうではありませんでした。
Martin v。Löwis、2015

70

big-O要件に特別な理由はありますか?それとも高速にしたいですか?sortedcontainersのモジュールは、純粋なPythonと高速(blistとrbtreeなど高速AS-Cの実装のように)です。

性能比較、それが速いかblistのソートされたリストのタイプと同等のベンチマークを示しています。rbtree、RBTree、およびPyAVLはソートされたdictおよびセットタイプを提供しますが、ソートされたリストタイプがないことにも注意してください。

パフォーマンスが要件である場合は、必ずベンチマークを行うことを忘れないでください。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

4
実際、sortedcontainerをbisectと比較し0.0845024989976ました。SortedList.add()0.596589182518とbisect.insort()を比較したため、速度が7倍になりました。また、sortedcontainers挿入ソートはO(log n)で動作し、bisect.insort()はO(n)で動作するため、リストの長さとともに速度ギャップが大きくなると予想しています。
15

1
@gaborous bisectはまだリストを使用しているため、挿入は残りますO(n)
njzk2

34

基本的な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リストは実際には配列です(たとえば、スキップリストなどではありません)。まあ、それは単純なものでなければならないと思いますが、私にとっては、名前は少し誤解を招くものです。


したがって、私が間違っていない場合、二分/リスト速度はおそらく次のようになります。

  • push()の場合:最悪の場合はO(n)。
  • 検索の場合:配列のインデックス作成の速度をO(1)と見なす場合、検索はO(log(n))操作でなければなりません。
  • リスト作成の場合:O(n)はリストのコピー速度でなければなりません。それ以外の場合は、同じリストのO(1)です)

更新。コメント欄での議論の後、私はここではこれらのSOの質問にリンクしてみましょう:どのようにPythonのリストが実装されているPythonのリスト機能の実行時の複雑さとは何ですか


リストはすでにソートされているため、push()はO(log n)にある必要があります。
estani

1
「挿入操作について」と言っておくべきだったかもしれません。とにかく、それは今、私は簡単に何か物事を混ぜるか、ミスすることができます約一年前だった
ジョージ

O(log n)のソートされたリストには常に値を挿入できます。バイナリ検索を参照してください。push()は挿入操作として定義されます。
estani

2
そうだね。しかし、挿入位置を見つけるには実際にO(log n)opsが必要ですが、実際の挿入(つまり、データ構造への要素の追加)はおそらくその構造に依存します(ソートされた配列に要素を挿入することを考えてください)。また、Pythonリストは実際には配列なので、O(n)がかかる場合があります。コメントのサイズ制限のため、回答のテキストから2つの関連するSO質問をリンクします(上記を参照)。
ジョージ

良い議論。Pythonで配列として処理される場所を知りませんでした。
estani 2012

7
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)です
j314erre

6

(まだ)カスタム検索機能を提供していませんが、heapqモジュールはあなたのニーズに合うかもしれません。通常のリストを使用してヒープキューを実装します。キューの内部構造を使用する独自の効率的なメンバーシップテストを作成する必要があります(O(log n)で実行できます)。欠点が1つあります。ソートされたリストの抽出には複雑さO(n log n)があります。


いいけど二分するのは難しい。
ilya n。

3
ヒープでO(log n)メンバーシップテストを実行するにはどうすればよいですか?値xを探している場合、xよりも大きい値を見つけた場合はブランチの検索を停止できますが、xのランダムな値の場合、葉にある可能性が50%あり、あまりプルーニングできません。
市場

1

biscectまたはsortedcontainersモジュールを使用します。私はあまり経験はありませんが、heapqモジュールは動作すると思います。含まれていますHeap Queue


0

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

50

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.