web-dev-qa-db-fra.com

Est-ce que python a une liste triée?

J'entends par là une structure avec:

  • O (log n) complexité pour les opérations x.Push()
  • O (log n) complexité pour trouver un élément
  • O (n) complexité à calculer list(x) qui sera triée

J'avais aussi une question connexe sur les performances de list(...).insert(...) qui est maintenant ici .

116
ilya n.

La liste standard Python n'est pas triée sous aucune forme. Le module standard heapq peut être utilisé pour ajouter en O (log n) à une liste existante et supprimer le plus petit un dans O (log n), mais n'est pas une liste triée dans votre définition.

Il existe différentes implémentations d’arbres équilibrés pour Python qui répondent à vos exigences, par exemple rbtree , RBTree ou pyavl =.

49
Martin v. Löwis

Existe-t-il une raison particulière pour vos exigences big-O? Ou voulez-vous simplement que ce soit rapide? Le module TrierContainers est pur-Python et rapide (comme dans les implémentations fast-as-C telles que Blist et rbtree).

Le comparaison des performances indique qu'il effectue des tests plus rapidement ou sur un pied d'égalité avec le type de liste triée de blist. Notez également que rbtree, RBTree et PyAVL fournissent des types dict et set triés mais qu’ils n’ont pas de type liste triée.

Si la performance est une exigence, souvenez-vous toujours de comparer. Un module qui corrobore l’allégation de rapidité avec la notation Big-O devrait être suspect jusqu’à ce qu’il présente également des comparaisons de points de référence.

Clause de non-responsabilité: Je suis l'auteur du module Python des conteneurs contenant.


Installation:

pip install sortedcontainers

Usage:

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

Bien que je n’aie toujours pas vérifié les "grosses O" vitesses des opérations de base Python list), le module standard bisect vaut également la peine d’être mentionné dans ce contexte:

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, désolé, bisect est mentionné dans la question mentionnée. Pourtant, je pense que ce ne sera pas très grave si cette information sera là)

PPS. Et Les listes CPython sont en fait des tableaux (pas, disons, les skiplists ou etc). Eh bien, je suppose qu'ils doivent être quelque chose de simple, mais quant à moi, le nom est un peu trompeur.


Donc, si je ne me trompe pas, les vitesses de bissect/liste seraient probablement:

  • pour un Push (): O(n) pour le pire des cas;
  • pour une recherche: si nous considérons que la vitesse d'indexation d'un tableau est O (1), la recherche devrait être une O(log(n)) opération;
  • pour la création de la liste: O(n) devrait être la vitesse de copie de la liste, sinon c'est O(1) pour la même liste)

Upd. Après une discussion dans les commentaires, laissez-moi mettre ici ces liens SO questions: Comment se fait La liste de Python est implémentée et Quelle est la complexité d'exécution de python fonctions de liste

31
ジョージ
import bisect

class sortedlist(list):
    '''just a list but with an insort (insert into sorted position)'''
    def insort(self, x):
        bisect.insort(self, x)
6
Dave31415

Bien qu'il ne fournisse pas (encore) de fonction de recherche personnalisée, le module heapq peut répondre à vos besoins. Il implémente une file d'attente de tas en utilisant une liste régulière. Vous devez écrire votre propre test d’effectif efficace qui utilise la structure interne de la file (ce qui peut être fait dans O (log n) , I je dirais ...). Il y a un inconvénient: l'extraction d'une liste triée est complexe O (n log n) .

6
Stephan202

J'utiliserais les modules biscect ou sortedcontainers. Je ne suis pas vraiment expérimenté, mais je pense que le module heapq fonctionne. Il contient un Heap Queue

1
Slass33

Il ne sera peut-être pas difficile d'implémenter votre propre liste de tri sur Python. Vous trouverez ci-dessous une preuve de concept:

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)

========= Résultats =============

[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

0
Fan