파이썬에는 정렬 된 목록이 있습니까?


128

이는 다음과 같은 구조를 의미합니다.

  • x.push()운영을 위한 O (log n) 복잡성
  • 요소를 찾기위한 O (log n) 복잡성
  • list(x)정렬 될 O (n) 복잡도 계산

또한 성능에 대한 관련 질문 list(...).insert(...)있습니다 .


memcpy여전히 O (n) 연산입니다. 파이썬이 어떻게 목록을 정확하게 구현하는지 잘 모르겠지만 , 내 생각에 그것들은 연속 된 메모리에 저장되어있을 것입니다. 그것이 실제로 그렇다면, bisect당신이 보여주는 삽입 은 복잡도 O (n) 입니다.
Stephan202

2
슬프게도 상자 밖으로 나오지 않습니다. 그러나 Grant Jenk의 분류 된 컨테이너 라이브러리는 훌륭합니다. stackoverflow.com/a/22616929/284795
Panic

답변:


52

표준 파이썬리스트는 어떤 형태로도 정렬되지 않습니다. 표준 heapq 모듈을 사용하여 기존 목록에 O (log n)를 추가하고 O (log n)에서 가장 작은 것을 제거 할 수 있지만 정의에서 정렬 된 목록은 아닙니다.

rbtree , RBTree 또는 pyavl같이 요구 사항을 충족하는 Python 용 균형 트리의 다양한 구현이 있습니다 .


1
rbtree의 경우 +1, 잘 작동합니다 (하지만 네이티브 코드를 포함합니다. 순수한 파이썬은 아니고 배포하기 쉽지 않습니다)
Will

12
sortedcontainers 는 성능 비교를 통해 순수 Python 및 rbtree와 같은 fast-as-C입니다.
GrantJ

"정의에서 정렬 된 목록이 아닙니다." 어떻게 요?
대령 패닉

4
heapq는 가장 작은 요소 만 찾을 수 있습니다. OP는 O (log n)에서 힙이 아닌 요소를 찾을 수있는 구조를 요구했습니다.
Martin v. Löwis

70

귀사의 요구 사항이 큰 특별한 이유가 있습니까? 아니면 그냥 빨리 하시겠습니까? sortedcontainers의 모듈 (blist rbtree와 같은 고속-C와 같은 구현에서와 같이) 고속 순수 파이썬하고있다.

성능 비교 쇼 더 빨리 또는에 파 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

4
실제로 분류 된 컨테이너를 bisect와 비교했습니다 : 0.0845024989976SortedList.add () 대 0.596589182518bisect.insort () 대 7x의 차이! 그리고 sortedcontainers 삽입 정렬은 O (log n)에서 작동하고 bisect.insort ()는 O (n)이므로 목록 길이에 따라 속도 차이가 증가 할 것으로 예상됩니다.
gaborous

1
bisect가 여전히 목록을 사용하기 때문에 @gaborousO(n)
njzk2

34

기본 파이썬 목록 작업의 "큰 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

추신. 아, 죄송합니다 bisect. 참조 된 질문에 언급되어 있습니다. 아직도, 나는이 정보가 여기에 있다면 크게 해를 끼치 지 않을 것이라고 생각합니다)

PPS. 그리고 CPython 목록은 실제로 배열입니다 (예 : skiplists 등). 글쎄, 나는 그들이 단순한 것이어야한다고 생각하지만, 나에게는 이름이 약간 오해의 소지가 있습니다.


따라서 내가 실수하지 않으면 bisect / list 속도는 아마도 다음과 같습니다.

  • push ()의 경우 : 최악의 경우 O (n);
  • 검색 : 배열 인덱싱 속도를 O (1)로 간주하면 검색은 O (log (n)) 연산이어야합니다.
  • 목록 생성의 경우 : O (n)은 목록 복사 속도 여야하며, 그렇지 않으면 동일한 목록에 대해 O (1)입니다.

Upd. 의견에 대한 토론에 이어 여기에 다음과 같은 질문을 링크 시키십시오 .Python의 List는 어떻게 구현 되고 파이썬 목록 함수의 런타임 복잡성은 무엇입니까?


목록이 이미 정렬되었으므로 push ()는 O (log n)에 있어야합니다.
estani

1
"insert op"에 대해 말 했어야 할 수도 있습니다 . 어쨌든, 그 년 정도했습니다 전 그래서 지금은 쉽게 일을하거나 미스 뭔가 혼합 할 수 있습니다
ジョージ

항상 O (log n)의 정렬 된 목록에 값을 삽입 할 수 있습니다 (이진 검색 참조). push ()는 삽입 작업으로 정의됩니다.
estani

2
진실. 그러나 삽입 위치 를 찾는 데 실제로 O (log n) ops가 필요하지만 실제 삽입 (예 : 데이터 구조에 요소 추가)은 해당 구조에 따라 다를 수 있습니다 (정렬 된 배열에 요소 삽입 생각). 로 그리고 파이썬 목록이 실제로 배열입니다 ,이 O (N)를 취할 수있다. 의견의 크기 제한으로 인해 답변 텍스트에서 두 가지 관련 SO 질문을 연결합니다 (위 참조).
ジ ョ ー ジ

좋은 주장. 파이썬에서 배열로 처리되는 목록을 알지 못했습니다.
estani

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의 묵시적 인서트 () O (N) 인
j314erre

6

사용자 정의 검색 기능을 제공하지는 않지만 heapq모듈은 사용자 요구에 적합 할 수 있습니다. 일반 목록을 사용하여 힙 큐를 구현합니다. 대기열의 내부 구조를 사용하는 효율적인 회원 자격 테스트를 작성해야합니다 ( O (log n) 에서 수행 할 수 있습니다 ...). 한 가지 단점이 있습니다. 정렬 된 목록을 추출하면 복잡도가 O (n log n) 입니다.


멋지지만 양분하기는 어렵습니다.
ilya n.

3
힙에 O (log n) 멤버쉽 테스트를 어떻게 수행 할 수 있습니까? x 값을 찾고 있다면 x보다 큰 것을 찾으면 가지를 내려다 볼 수 없지만 x의 임의 값의 경우 잎에있을 확률이 50 %이며 많이자를 수는 없습니다.
시장 :

1

biscect또는 sortedcontainers모듈을 사용합니다 . 나는 실제로 경험이 없지만 heapq모듈이 작동 한다고 생각 합니다. 그것은 포함Heap Queue


0

파이썬에서 자체 정렬 목록을 구현하는 것은 어렵지 않을 수 있습니다. 아래는 개념 증명입니다.

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.