Bu, Python 3.41 A setinin kopya olarak kapatılmasından önce verilen bir yanıttır .
Diğerleri haklı: siparişe güvenmeyin. Bir tane varmış gibi yapma.
Bununla birlikte, güvenebileceğiniz bir şey var:
list(myset) == list(myset)
Yani, düzen kararlıdır .
Neden algılanan bir düzen olduğunu anlamak için birkaç şeyin anlaşılması gerekir:
Üstten:
Bir karma seti gerçekten hızlı arama süreleri ile rastgele veri saklama yöntemidir.
Bir destek dizisi vardır:
# A C array; items may be NULL,
# a pointer to an object, or a
# special dummy object
_ _ 4 _ _ 2 _ _ 6
Bu setlerden çıkarmayacağımız için, yalnızca kaldırmaları daha kolay halletmek için var olan özel kukla nesneyi görmezden geleceğiz.
Gerçekten hızlı bir arama yapmak için, bir nesneden bir karma hesaplamak için biraz sihir yaparsınız. Tek kural, eşit olan iki nesnenin aynı karmaya sahip olmasıdır. (Ancak iki nesne aynı karmaya sahipse, eşit olmayabilir.)
Ardından, modülü dizi uzunluğuna göre alarak dizini oluşturursunuz:
hash(4) % len(storage) = index 2
Bu, öğelere erişmeyi gerçekten hızlı hale getirir.
Hash'ler olarak, hikayenin sadece çoğu hash(n) % len(storage)
ve hash(m) % len(storage)
aynı sayıda neden olabilir. Bu durumda, birkaç farklı strateji çatışmayı çözmeyi deneyebilir. CPython, karmaşık şeyler yapmadan önce 9 kez "lineer problama" kullanır, bu nedenle başka bir yere bakmadan önce 9 yere kadar yuvanın soluna bakacaktır .
CPython'un karma setleri şu şekilde saklanır:
Bir karma seti en fazla 2/3 dolu olabilir . 20 öğe varsa ve destek dizisi 30 öğe uzunluğunda ise, destek deposu daha büyük olacak şekilde yeniden boyutlandırılır. Bunun nedeni, küçük destek mağazalarıyla çarpışmaları daha sık görmeniz ve çarpışmaların her şeyi yavaşlatmasıdır.
Destek deposu, ikisinin gücü ile yeniden boyutlandırılan büyük setler (50k elemanlar) hariç, 8'den başlayarak 4'lük güçlerde yeniden boyutlandırılır: (8, 32, 128, ...).
Yani bir dizi oluşturduğunuzda, destek deposu uzunluk 8'dir. 5 dolu olduğunda ve bir öğe eklediğinizde, kısaca 6 öğe içerecektir. 6 > ²⁄₃·8
böylece bu yeniden boyutlandırmayı tetikler ve destek deposu 32 boyuta dört katına çıkar.
Son olarak, hash(n)
sadece n
sayılar için döner ( -1
özel olanlar hariç ).
Öyleyse, ilkine bakalım:
v_set = {88,11,1,33,21,3,7,55,37,8}
len(v_set)
10'dur, bu nedenle tüm mağazalar eklendikten sonra destek mağazası en az 15 (+1) olur . 2'nin ilgili gücü 32'dir. Yani destek mağazası:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
Sahibiz
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
böylece bunlar şu şekilde eklenir:
__ 1 __ 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
33 ← Can't also be where 1 is;
either 1 or 33 has to move
Yani biz gibi bir sipariş beklenir
{[1 or 33], 3, 37, 7, 8, 11, 21, 55, 88}
başka bir yerde başlangıçta olmayan 1 veya 33 ile. Bu doğrusal problama kullanır, bu yüzden ya:
↓
__ 1 33 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
veya
↓
__ 33 1 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
33'ün yerinden edilmiş olanı olmasını bekleyebilirsiniz, çünkü 1 zaten oradaydı, ancak set inşa edilirken gerçekleşen yeniden boyutlandırma nedeniyle, aslında durum böyle değil. Set her yeniden oluşturulduğunda, daha önce eklenmiş olan eşyalar etkili bir şekilde yeniden sıralanır.
Şimdi nedenini görebilirsiniz
{7,5,11,1,4,13,55,12,2,3,6,20,9,10}
olabilir. 14 element var, bu yüzden destek mağazası en az 21 + 1, yani 32:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
İlk 13 yuvada 1 ila 13 karma. 20, yuva 20'ye gider.
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ __ __ __ __ __ __ __ __ __
55 hash(55) % 32
, 23 olan yuvaya gider :
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ 55 __ __ __ __ __ __ __ __
Bunun yerine 50 tane seçseydik,
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ 50 __ 20 __ __ __ __ __ __ __ __ __ __ __
Ve bakalım:
{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
şeylerin görünüşüyle oldukça basit bir şekilde uygulanır: listeyi dolaşır ve birincisini açar.
Bunların hepsi uygulama detayı.