นี่เป็นการตอบสนองต่อPython 3.41 มากกว่าชุดก่อนที่จะถูกปิดเป็นชุดซ้ำ
อื่น ๆ ถูกต้อง: อย่าพึ่งพาคำสั่งซื้อ อย่าแม้แต่จะแกล้งทำเป็นว่ามีอยู่จริง
ที่กล่าวว่ามีสิ่งหนึ่งที่คุณสามารถพึ่งพาคือ:
list(myset) == list(myset)
นั่นคือการสั่งซื้อที่มีเสถียรภาพ
การทำความเข้าใจว่าทำไมจึงมีคำสั่งที่รับรู้ต้องการความเข้าใจเล็ก ๆ น้อย ๆ :
จากด้านบน:
ชุดกัญชาเป็นวิธีการในการจัดเก็บข้อมูลแบบสุ่มกับเวลาจริงๆค้นหาได้อย่างรวดเร็ว
มันมีอาร์เรย์สำรอง:
# A C array; items may be NULL,
# a pointer to an object, or a
# special dummy object
_ _ 4 _ _ 2 _ _ 6
เราจะไม่สนใจวัตถุจำลองพิเศษซึ่งมีอยู่เพียงเพื่อให้การกำจัดง่ายขึ้นเนื่องจากเราจะไม่ถูกลบออกจากชุดเหล่านี้
เพื่อให้มีการค้นหาที่รวดเร็วจริงๆคุณต้องใช้เวทมนตร์เพื่อคำนวณแฮชจากวัตถุ กฎข้อเดียวคือวัตถุสองชิ้นที่เท่ากันมีแฮชเดียวกัน (แต่ถ้าวัตถุสองชิ้นมีแฮชเดียวกันพวกมันอาจไม่เท่ากัน)
จากนั้นคุณสร้างในดัชนีโดยการมอดุลัสตามความยาวของอาร์เรย์:
hash(4) % len(storage) = index 2
สิ่งนี้ทำให้เข้าถึงองค์ประกอบได้อย่างรวดเร็ว
แฮชเป็นเพียงเรื่องราวส่วนใหญ่เท่านั้นhash(n) % len(storage)
และhash(m) % len(storage)
อาจส่งผลให้มีจำนวนเท่ากัน ในกรณีดังกล่าวกลยุทธ์ที่แตกต่างกันสามารถลองและแก้ไขข้อขัดแย้งได้ CPython ใช้ "การสำรวจเชิงเส้น" 9 ครั้งก่อนที่จะทำสิ่งที่ซับซ้อนดังนั้นมันจะดูทางด้านซ้ายของช่องใส่ได้ถึง 9 แห่งก่อนที่จะมองไปที่อื่น
ชุดแฮชของ CPython ถูกเก็บไว้ในลักษณะนี้:
ชุดกัญชาสามารถไม่เกิน 2/3 หากมี 20 องค์ประกอบและอาร์เรย์สำรองยาว 30 องค์ประกอบหน่วยเก็บข้อมูลสำรองจะปรับขนาดให้ใหญ่ขึ้น นี่เป็นเพราะคุณได้รับการชนบ่อยขึ้นด้วยร้านค้าสำรองขนาดเล็กและการชนกันทำให้ทุกอย่างช้าลง
ที่เก็บข้อมูลสำรองปรับขนาดด้วยพลังของ 4 เริ่มต้นที่ 8 ยกเว้นชุดขนาดใหญ่ (องค์ประกอบ 50k) ซึ่งปรับขนาดในพลังของสอง: (8, 32, 128, ... )
ดังนั้นเมื่อคุณสร้างอาร์เรย์ที่เก็บข้อมูลสำรองจะมีความยาว 8 เมื่อเต็ม 5 และคุณเพิ่มองค์ประกอบมันจะมีองค์ประกอบ 6 รายการ 6 > ²⁄₃·8
ดังนั้นสิ่งนี้ทริกเกอร์การปรับขนาดและที่เก็บข้อมูลสำรองเพิ่มเป็นสี่เท่าของขนาด 32
ในที่สุดhash(n)
ก็แค่ส่งกลับn
สำหรับตัวเลข (ยกเว้น-1
ที่พิเศษ)
ดังนั้นเรามาดูสิ่งแรก:
v_set = {88,11,1,33,21,3,7,55,37,8}
len(v_set)
เท่ากับ 10 ดังนั้นที่เก็บข้อมูลสำรองอย่างน้อย 15 (+1) หลังจากเพิ่มรายการทั้งหมดแล้ว พลังที่เกี่ยวข้องของ 2 คือ 32 ดังนั้นที่เก็บสำรองคือ:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
เรามี
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
ดังนั้นการแทรกเหล่านี้เป็น:
__ 1 __ 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
33 ← Can't also be where 1 is;
either 1 or 33 has to move
ดังนั้นเราคาดหวังคำสั่งเช่นนั้น
{[1 or 33], 3, 37, 7, 8, 11, 21, 55, 88}
ด้วย 1 หรือ 33 ที่ไม่ได้เป็นจุดเริ่มต้นที่อื่น สิ่งนี้จะใช้การตรวจเชิงเส้นดังนั้นเราจะได้:
↓
__ 1 33 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
หรือ
↓
__ 33 1 3 __ 37 __ 7 8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
คุณอาจคาดหวังว่า 33 คนนั้นจะเป็นคนที่พลัดพรากเพราะ 1 อยู่ที่นั่นแล้ว แต่เนื่องจากการปรับขนาดที่เกิดขึ้นเมื่อชุดกำลังถูกสร้างขึ้นนี่ไม่ใช่เรื่องจริง ทุกครั้งที่ชุดสร้างใหม่รายการที่เพิ่มไปแล้วจะถูกจัดลำดับใหม่อย่างมีประสิทธิภาพ
ตอนนี้คุณสามารถดูว่าทำไม
{7,5,11,1,4,13,55,12,2,3,6,20,9,10}
อาจจะอยู่ในลำดับ มี 14 องค์ประกอบดังนั้นที่เก็บข้อมูลสำรองอย่างน้อย 21 + 1 ซึ่งหมายถึง 32:
__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
1 ถึง 13 แฮชใน 13 ช่องแรก 20 ไปในสล็อต 20
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ __ __ __ __ __ __ __ __ __
55 ไปในสล็อตhash(55) % 32
ซึ่งคือ 23:
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ __ __ 20 __ __ 55 __ __ __ __ __ __ __ __
หากเราเลือก 50 แทนเราคาดหวัง
__ 1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ __ __ 50 __ 20 __ __ __ __ __ __ __ __ __ __ __
และแท้จริงและดูเถิด:
{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
มีการใช้งานค่อนข้างง่ายโดยลักษณะของสิ่งต่าง ๆ : มันสำรวจรายการและผุดรายการแรก
นี่คือรายละเอียดการใช้งานทั้งหมด