Đây là một phản hồi nhiều hơn cho Python 3.41 Một tập hợp trước khi nó được đóng lại dưới dạng trùng lặp.
Những người khác là đúng: không dựa vào thứ tự. Thậm chí đừng giả vờ có một.
Điều đó nói rằng, có một điều bạn có thể dựa vào:
list(myset) == list(myset)
Đó là, trật tự ổn định .
Hiểu lý do tại sao có một trật tự nhận thức đòi hỏi phải hiểu một số điều:
Python đó sử dụng các bộ băm ,
Cách bộ băm của CPython được lưu trữ trong bộ nhớ và
Làm thế nào các số được băm
Từ đầu trang:
Một bộ băm là một phương pháp lưu trữ dữ liệu ngẫu nhiên với thời gian tra cứu thực sự nhanh chóng.
Nó có một mảng sao lưu:
# A C array; items may be NULL,
# a pointer to an object, or a
# special dummy object
_ _ 4 _ _ 2 _ _ 6
Chúng ta sẽ bỏ qua đối tượng giả đặc biệt, chỉ tồn tại để giúp loại bỏ dễ dàng hơn để xử lý, vì chúng ta sẽ không xóa khỏi các bộ này.
Để có một tra cứu thực sự nhanh chóng, bạn thực hiện một số phép thuật để tính toán hàm băm từ một đối tượng. Quy tắc duy nhất là hai đối tượng bằng nhau có cùng hàm băm. (Nhưng nếu hai đối tượng có cùng hàm băm thì chúng có thể không bằng nhau.)
Sau đó, bạn thực hiện chỉ mục bằng cách lấy mô-đun theo độ dài mảng:
hash(4) % len(storage) = index 2
Điều này làm cho nó thực sự nhanh chóng để truy cập các yếu tố.
Băm chỉ là hầu hết các câu chuyện, hash(n) % len(storage)
và hash(m) % len(storage)
có thể dẫn đến cùng một số. Trong trường hợp đó, một số chiến lược khác nhau có thể thử và giải quyết xung đột. CPython sử dụng "thăm dò tuyến tính" 9 lần trước khi thực hiện những việc phức tạp, do đó, nó sẽ nhìn sang bên trái của vị trí cho tối đa 9 địa điểm trước khi tìm nơi khác.
Các bộ băm của CPython được lưu trữ như thế này:
Một bộ băm có thể không quá 2/3 . Nếu có 20 phần tử và mảng sao lưu dài 30 phần tử, cửa hàng sao lưu sẽ thay đổi kích thước để lớn hơn. Điều này là do bạn bị va chạm thường xuyên hơn với các cửa hàng nhỏ, và va chạm làm chậm mọi thứ.
Cửa hàng sao lưu thay đổi kích thước theo quyền hạn 4, bắt đầu từ 8, ngoại trừ các bộ lớn (50k phần tử) thay đổi kích thước theo quyền hạn của hai: (8, 32, 128, ...).
Vì vậy, khi bạn tạo một mảng, cửa hàng sao lưu có độ dài 8. Khi nó đầy đủ 5 và bạn thêm một phần tử, nó sẽ chứa ngắn gọn 6 phần tử. 6 > ²⁄₃·8
vì vậy, điều này kích hoạt thay đổi kích thước và cửa hàng sao lưu tăng gấp bốn lần kích thước 32.
Cuối cùng, hash(n)
chỉ trả về n
số (trừ trường hợp -1
đặc biệt).
Vì vậy, hãy nhìn vào cái đầu tiên:
v_set = {88,11,1,33,21,3,7,55,37,8}
len(v_set)
là 10, vì vậy cửa hàng sao lưu ít nhất là 15 (+1) sau khi tất cả các mục đã được thêm vào . Sức mạnh liên quan của 2 là 32. Vì vậy, cửa hàng sao lưu là:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
Chúng ta có
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
vì vậy những chèn như:
__ 1 __ 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
33 ← Can't also be where 1 is;
either 1 or 33 has to move
Vì vậy, chúng tôi mong đợi một đơn đặt hàng như
{[1 or 33], 3, 37, 7, 8, 11, 21, 55, 88}
với 1 hoặc 33 không bắt đầu ở một nơi khác. Điều này sẽ sử dụng thăm dò tuyến tính, vì vậy chúng ta sẽ có:
↓
__ 1 33 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
hoặc là
↓
__ 33 1 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
Bạn có thể mong đợi 33 sẽ là người bị thay thế bởi vì 1 đã ở đó, nhưng do việc thay đổi kích thước xảy ra khi bộ đang được xây dựng, thực tế không phải vậy. Mỗi khi bộ được xây dựng lại, các mục đã thêm sẽ được sắp xếp lại một cách hiệu quả.
Bây giờ bạn có thể thấy tại sao
{7,5,11,1,4,13,55,12,2,3,6,20,9,10}
có thể theo thứ tự. Có 14 yếu tố, vì vậy cửa hàng sao lưu ít nhất là 21 + 1, có nghĩa là 32:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
1 đến 13 băm trong 13 vị trí đầu tiên. 20 đi vào khe 20.
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ __ __ __ __ __ __ __ __ __
55 đi trong khe hash(55) % 32
là 23:
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ 55 __ __ __ __ __ __ __ __
Nếu chúng tôi chọn 50 thay vào đó, chúng tôi sẽ mong đợi
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ 50 __ 20 __ __ __ __ __ __ __ __ __ __ __
Và lo và kìa:
{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
được thực hiện khá đơn giản bởi vẻ bề ngoài của mọi thứ: nó đi qua danh sách và bật cái đầu tiên.
Đây là tất cả các chi tiết thực hiện.