Python'da sıralanmış bir liste var mı?


128

Bununla bir yapıyı kastediyorum:

  • x.push()İşlemler için O (log n) karmaşıklığı
  • Bir eleman bulmak için O (log n) karmaşıklığı
  • list(x)Sıralanacak olan hesaplamak için O (n) karmaşıklığı

Ayrıca performansıyla ilgili list(...).insert(...)şu anda burada olan bir sorum vardı .


memcpyhala bir O (n) işlemidir. Python'un listeleri tam olarak nasıl uyguladığından emin değilim , ama benim iddiam bunların bitişik bellekte saklanması (kesinlikle bağlantılı bir liste olarak değil) olacaktır. Eğer gerçekten böyleyse, kullanarak bisectgösterdiğiniz ekleme karmaşıklığı O (n) olacaktır .
Stephan202

2
Ne yazık ki kutunun dışında değil. Ama Grant Jenk'in sınıflandırılmış konteyner kütüphanesi mükemmel. stackoverflow.com/a/22616929/284795
Colonel Panic

Yanıtlar:


52

Standart Python listesi herhangi bir biçimde sıralanmamıştır. Standart heapq modülü, O (log n) 'yi mevcut bir listeye eklemek ve O (log n)' deki en küçük olanı kaldırmak için kullanılabilir, ancak tanımınızda sıralı bir liste değildir.

Python için gereksinimlerinizi karşılayan çeşitli dengeli ağaç uygulamaları vardır, örneğin rbtree , RBTree veya pyavl .


1
Rbtree için 1, çok iyi çalışıyor (ama yerel kod içerir, değil saf piton, o kadar kolay belki dağıtmak)
Will

12
sıralanmışcontainers , performans karşılaştırması ile saf Python ve C kadar hızlıdır (rbtree gibi).
GrantJ

"tanımınızda sıralı bir liste değil." Nasıl yani?
Albay Panik

4
heapq yalnızca en küçük öğeyi bulmaya izin verir; OP, O (log n) 'de yığınların bulunmayan herhangi bir elemanı bulabilen bir yapı istiyordu.
Martin - Löwis

70

Büyük gereksinimlerinizin özel bir nedeni var mı? Yoksa sadece hızlı olmasını mı istiyorsun? Sortedcontainers modülü (Blist ve rbtree gibi hızlı olarak-C uygulamalarında olduğu gibi) hızlı saf-piton ve bir.

Performans karşılaştırma gösterileri daha hızlı veya üzerinde par Blist en sıralı liste türüyle kriterler. Ayrıca rbtree, RBTree ve PyAVL'nin sıralı dikte ve set türleri sağladığını ancak sıralı bir liste türüne sahip olmadığını unutmayın.

Performans bir gereklilikse, her zaman kıyaslamayı unutmayın. Big-O notasyonu ile hızlı olma iddiasını doğrulayan bir modül, kıyaslama karşılaştırmalarını da gösterene kadar şüpheli olmalıdır.

Sorumluluk Reddi: Python sıralanmış kaplar modülünün yazarıyım.


Kurulum:

pip install sortedcontainers

Kullanımı:

>>> from sortedcontainers import SortedList
>>> l = SortedList()
>>> l.update([0, 4, 1, 3, 2])
>>> l.index(3)
3
>>> l.add(5)
>>> l[-1]
5

4
Aslında sıralanmış konteynerleri bisect ile karşılaştırdım: 0.0845024989976SortedList.add () ve 0.596589182518bisect.insort () için, bu nedenle hızda 7x fark! Sıralı kapsayıcılar ekleme sıralaması O (log n), bisect.insort () ise O (n) içinde çalıştığından, hız aralığının liste uzunluğuyla artmasını bekliyorum.
gaborous

1
@gaborous çünkü bisect hala bir liste kullanıyor, bu yüzden ekleme kalıyorO(n)
njzk2

34

Temel Python listesi işlemlerinin "büyük O" hızlarını hala hiç kontrol etmemiş olsam da, bisectstandart modül muhtemelen bu bağlamda bahsetmeye değer:

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. Ah, üzgünüm, bisectbaşvurulan soruda bahsediliyor. Yine de, bu bilginin burada olmasının pek bir zararı olmayacağını düşünüyorum)

PPS. Ve CPython listeleri aslında dizilerdir (örneğin, skiplists vb. Değil). Sanırım basit bir şey olmalılar, ama bana gelince, isim biraz yanıltıcı.


Yani, yanılmıyorsam, ikiye bölme / liste hızları muhtemelen şöyle olacaktır:

  • bir itme () için: En kötü durum için O (n);
  • bir arama için: dizi indeksleme hızının O (1) olduğunu düşünürsek, arama bir O (log (n)) işlemi olmalıdır;
  • liste oluşturma için: O (n) liste kopyalama hızı olmalıdır, aksi takdirde aynı liste için O (1) olur)

Post. Yorumlardaki bir tartışmanın ardından, şu SO sorularını buraya bağlamama izin verin: Python'un Listesi Nasıl Uygulanır ve python listesi işlevlerinin çalışma zamanı karmaşıklığı nedir


liste halihazırda sıralandığı için push () O (log n) içinde olmalıdır.
estani

1
Belki de "ekleme operasyonu için" demeliydim . her neyse, bu yaklaşık bir yıl önceydi, bu yüzden şimdi bir şeyleri kolayca karıştırabilir veya bir şeyleri gözden kaçırabilirim
ジ ョ ー ジ

O (log n) 'de sıralı bir listeye her zaman bir değer ekleyebilirsiniz, bkz. İkili arama. push () bir ekleme işlemi olarak tanımlanır.
estani

2
Doğru. Ancak , ekleme konumunu bulmak gerçekten O (log n) işlemlerini alırken, gerçek ekleme (yani öğeyi veri yapısına eklemek) muhtemelen bu yapıya bağlıdır (sıralı bir diziye bir öğe eklemeyi düşünün). Ve Python listeleri aslında diziler olduğundan , bu O (n) alabilir. Yorumların boyut sınırı nedeniyle, iki ilgili SO sorusunu yanıt metninden bağlayacağım (yukarıya bakın).
ジ ョ ー ジ

İyi tartışma. Python'da diziler olarak ele alınan listenin farkında değildim.
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 () içindeki ima edilen insert () O (n)
j314erre

6

heapqModül , (henüz) özel bir arama işlevi sağlamasa da , ihtiyaçlarınızı karşılayabilir. Normal bir liste kullanarak bir yığın kuyruğu uygular. Kuyruğun iç yapısını kullanan kendi verimli üyelik testinizi yazmanız gerekir (bu O (log n) ' de yapılabilir , diyebilirim ki ...). Bir dezavantajı var: sıralı bir listeyi çıkarmanın karmaşıklığı O (n log n) .


Güzel ama ikiye bölünmesi zor.
ilya n.

3
Bir yığın içinde O (log n) üyelik testi nasıl olabilir? Eğer x değerini arıyorsanız, x'ten daha büyük bir şey bulursanız bir daldan aşağı bakmayı bırakabilirsiniz, ancak rastgele bir x değeri için bu% 50 olasılıkla bir yaprağa gidebilir ve muhtemelen fazla budama yapamazsınız.
pazarlar

1

Ben kullanacağı biscectveya sortedcontainersmodülleri. Gerçekten tecrübeli değilim ama heapqmodülün işe yaradığını düşünüyorum . İçerirHeap Queue


0

Python'da kendi sıralama listenizi uygulamak zor olmayabilir. Aşağıda bir kavram kanıtı verilmiştir:

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)

========= Sonuçlar ============

[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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.