Dies ist eher eine Antwort auf Python 3.41 Ein Satz, bevor er als Duplikat geschlossen wurde.
Die anderen haben Recht: Verlassen Sie sich nicht auf die Bestellung. Tu nicht einmal so, als gäbe es einen.
Es gibt jedoch eine Sache, auf die Sie sich verlassen können:
list(myset) == list(myset)
Das heißt, die Reihenfolge ist stabil .
Um zu verstehen, warum es eine wahrgenommene Ordnung gibt, müssen einige Dinge verstanden werden:
Dass Python Hash-Sets verwendet ,
Wie CPythons Hash-Set im Speicher gespeichert wird und
Wie Zahlen gehasht werden
Von oben:
Ein Hash-Set ist eine Methode zum Speichern von Zufallsdaten mit sehr schnellen Suchzeiten.
Es hat ein Hintergrundarray:
# A C array; items may be NULL,
# a pointer to an object, or a
# special dummy object
_ _ 4 _ _ 2 _ _ 6
Wir werden das spezielle Dummy-Objekt ignorieren, das nur existiert, um das Behandeln von Entfernungen zu vereinfachen, da wir nicht aus diesen Mengen entfernen werden.
Um wirklich schnell nachschlagen zu können, zaubern Sie einen Hash aus einem Objekt. Die einzige Regel ist, dass zwei Objekte, die gleich sind, denselben Hash haben. (Wenn jedoch zwei Objekte denselben Hash haben, können sie ungleich sein.)
Sie erstellen dann einen Index, indem Sie den Modul anhand der Arraylänge nehmen:
hash(4) % len(storage) = index 2
Dies macht es sehr schnell, auf Elemente zuzugreifen.
Hashes sind nur die meisten der Geschichte, wie hash(n) % len(storage)
und hash(m) % len(storage)
in gleicher Anzahl zur Folge haben kann. In diesem Fall können verschiedene Strategien versuchen, den Konflikt zu lösen. CPython verwendet 9-mal "lineares Prüfen", bevor komplizierte Dinge ausgeführt werden. Daher wird links vom Slot nach bis zu 9 Stellen gesucht, bevor nach einer anderen Stelle gesucht wird.
CPythons Hash-Sets werden wie folgt gespeichert:
Ein Hash-Set darf nicht mehr als 2/3 voll sein . Wenn 20 Elemente vorhanden sind und das Hintergrundarray 30 Elemente lang ist, wird die Größe des Hintergrundspeichers größer. Dies liegt daran, dass Kollisionen mit kleinen Backing-Stores häufiger auftreten und Kollisionen alles verlangsamen.
Die Größe des Hintergrundspeichers wird in Potenzen von 4 beginnend bei 8 geändert, mit Ausnahme von großen Sätzen (50.000 Elemente), deren Größe in Zweierpotenzen geändert wird: (8, 32, 128, ...).
Wenn Sie also ein Array erstellen, hat der Hintergrundspeicher die Länge 8. Wenn er 5 voll ist und Sie ein Element hinzufügen, enthält er kurz 6 Elemente. 6 > ²⁄₃·8
Dies löst also eine Größenänderung aus, und der Hintergrundspeicher vervierfacht sich auf Größe 32.
Schließlich wird hash(n)
nur n
für Zahlen zurückgegeben (außer -1
was speziell ist).
Schauen wir uns also den ersten an:
v_set = {88,11,1,33,21,3,7,55,37,8}
len(v_set)
ist 10, also ist der Hintergrundspeicher mindestens 15 (+1), nachdem alle Elemente hinzugefügt wurden . Die relevante Potenz von 2 ist 32. Der Hintergrundspeicher lautet also:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
Wir haben
hash(88) % 32 = 24
hash(11) % 32 = 11
hash(1) % 32 = 1
hash(33) % 32 = 1
hash(21) % 32 = 21
hash(3) % 32 = 3
hash(7) % 32 = 7
hash(55) % 32 = 23
hash(37) % 32 = 5
hash(8) % 32 = 8
also diese einfügen als:
__ 1 __ 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
33 ← Can't also be where 1 is;
either 1 or 33 has to move
Wir würden also eine Bestellung wie erwarten
{[1 or 33], 3, 37, 7, 8, 11, 21, 55, 88}
mit der 1 oder 33 ist das nicht woanders am Start. Dies wird eine lineare Abtastung verwenden, also haben wir entweder:
↓
__ 1 33 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
oder
↓
__ 33 1 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
Sie können erwarten, dass die 33 diejenige ist, die verschoben wurde, weil die 1 bereits vorhanden war. Aufgrund der Größenänderung, die beim Erstellen des Sets auftritt, ist dies jedoch nicht der Fall. Jedes Mal, wenn das Set neu erstellt wird, werden die bereits hinzugefügten Elemente effektiv neu angeordnet.
Jetzt können Sie sehen warum
{7,5,11,1,4,13,55,12,2,3,6,20,9,10}
könnte in Ordnung sein. Es gibt 14 Elemente, sodass der Hintergrundspeicher mindestens 21 + 1 beträgt, was 32 bedeutet:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
1 bis 13 Hash in den ersten 13 Slots. 20 geht in Steckplatz 20.
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ __ __ __ __ __ __ __ __ __
55 geht in Slot, hash(55) % 32
der 23 ist:
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ 55 __ __ __ __ __ __ __ __
Wenn wir stattdessen 50 wählen würden, würden wir erwarten
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ 50 __ 20 __ __ __ __ __ __ __ __ __ __ __
Und siehe da:
{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 20, 50}
#>>> {1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 50, 20}
pop
wird ganz einfach durch das Aussehen der Dinge implementiert: Es durchläuft die Liste und öffnet die erste.
Dies ist alles Implementierungsdetail.