(เมื่อใด) คือการค้นหาตารางแฮช O (1)?


70

มักจะกล่าวว่าการค้นหาตารางแฮชทำงานในเวลาคงที่: คุณคำนวณค่าแฮชซึ่งให้ดัชนีสำหรับการค้นหาอาร์เรย์ แต่สิ่งนี้ไม่สนใจการชน ในกรณีที่เลวร้ายที่สุดทุกรายการเกิดขึ้นในถังเดียวกันและเวลาค้นหากลายเป็นเชิงเส้น ( )Θ(n)

มีเงื่อนไขเกี่ยวกับข้อมูลที่สามารถทำการค้นหาตารางแฮชอย่างแท้จริงหรือไม่ เป็นค่าเฉลี่ยเท่านั้นหรือตารางแฮชมีค้นหาตัวพิมพ์ที่เลวร้ายที่สุด?O ( 1 )O(1)O(1)

หมายเหตุ: ฉันมาจากมุมมองของโปรแกรมเมอร์ที่นี่ เมื่อฉันเก็บข้อมูลในตารางแฮชมันมักจะเป็นสตริงหรือโครงสร้างข้อมูลคอมโพสิตบางส่วนและข้อมูลจะเปลี่ยนแปลงในช่วงอายุของตารางแฮช ดังนั้นในขณะที่ฉันชื่นชมคำตอบเกี่ยวกับแฮ็กที่สมบูรณ์แบบพวกเขาน่ารัก แต่เป็นข้อมูลเล็ก ๆ น้อย ๆ และไม่สามารถใช้งานได้จริงจากมุมมองของฉัน

การติดตามผล PS: ข้อมูลประเภทใดที่มีการดำเนินการตารางแฮช O (1)


3
คุณอยู่กับเวลาเข้าถึงที่ถูกตัดจำหน่ายได้หรือไม่? โดยทั่วไปประสิทธิภาพของตารางแฮชจะขึ้นอยู่กับจำนวนค่าใช้จ่ายที่มากสำหรับแฮชเทเบิลที่คุณเตรียมที่จะทนและวิธีการกระจายค่าแฮชจริง O(1)
Raphael

5
โอ้ btw: คุณสามารถหลีกเลี่ยงพฤติกรรมเชิงเส้นที่แย่ที่สุดโดยใช้แผนผังการค้นหา (สมดุล) แทนที่จะเป็นรายการ
Raphael

1
@ ราฟาเอลฉันจะสนใจคำตอบที่อธิบาย (ตามเส้นกว้าง) เมื่อฉันสามารถนับตัดจำหน่ายและเมื่อฉันไม่สามารถ สำหรับวิธีการกระจายค่าแฮชนี่เป็นส่วนหนึ่งของคำถามของฉันจริง ๆ : ฉันจะรู้ได้อย่างไร ฉันรู้ว่าฟังก์ชันแฮชควรแจกจ่ายค่าได้ดี แต่ถ้าพวกเขาทำคดีที่เลวร้ายที่สุดจะไม่สามารถเข้าถึงได้ซึ่งไม่สมเหตุสมผล O(1)
Gilles

1
ระวังการเพิ่มประสิทธิภาพก่อนเวลาอันควร สำหรับข้อมูลขนาดเล็ก (หลายพันองค์ประกอบ) ฉันเห็นต้นไม้ไบนารีที่สมดุลกันดีกว่า hashtables เนื่องจากค่าใช้จ่ายต่ำกว่า (การเปรียบเทียบสตริงมีราคาถูกกว่าแฮชสตริง) O(logn)
isturdy

ขอให้เรายังคงอภิปรายนี้ในการแชท
กราฟิลส์

คำตอบ:


41

มีการตั้งค่าสองแบบที่คุณสามารถได้รับเลวร้ายที่สุดO(1)

  1. ถ้าการตั้งค่าของคุณเป็นแบบคงที่แล้ว FKS คร่ำเครียดคุณจะได้รับเลวร้ายที่สุดกรณีการค้ำประกัน แต่ตามที่คุณระบุการตั้งค่าของคุณไม่คงที่O(1)

  2. หากคุณใช้การแฮ็ก Cuckoo ดังนั้นข้อความค้นหาและการลบจะเป็นกรณีที่แย่ที่สุด แต่การแทรกนั้นเป็นเพียงคาดไว้ การแฮชของนกกาเหว่าทำได้ค่อนข้างดีถ้าคุณมีส่วนบนของจำนวนเม็ดมีดทั้งหมดและกำหนดขนาดของโต๊ะให้ใหญ่ขึ้นประมาณ 25%O ( 1 )O(1)O(1)

มีข้อมูลเพิ่มเติมเป็นที่นี่


3
คุณช่วยขยาย FKS และ Cuckoo ได้ไหม? คำศัพท์ทั้งสองเป็นสิ่งใหม่สำหรับฉัน
Gilles

1
สิ่งที่เกี่ยวกับการแปลงแป้นพิมพ์ที่สมบูรณ์แบบแบบไดนามิก? มันมีการค้นหากรณีที่เลวร้ายที่สุดและแทรกและการลบค่าตัดจำหน่าย ( citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.30.8165 )O ( 1 )O(1)O(1)
Joe

2
FKS เป็นชื่อย่อของ (Fredman, Komlós, Szemerédi) และ Cuckoo เป็นชื่อของสายพันธุ์บริดจ์ มันใช้สำหรับการบีบแตรประเภทนี้เนื่องจากลูกไก่นกกาเหว่าผลักไข่ sibilings ออกจากรัง วิธีนี้คล้ายกับว่ามีวิธีการทำงานอย่างไร
uli

1
@Suresh: จริงเหรอ? ฉันคิดว่าคุณต้องการฟังก์ชั่นอิสระซึ่งฉันมักจะเกี่ยวข้องกับการขยายที่จำเป็น ฉันยืนแก้ไขแล้ว จะลบความคิดเห็นของฉันเล็กน้อย logn
หลุยส์

1
เพื่อให้ความคิดเห็นที่มีประโยชน์มากขึ้นกับคำตอบนี้เนื่องจาก @Suresh ชี้ให้เห็นว่าการแฮ็กแฮ็คจะทำงานได้ดีโดยไม่ต้องใช้ฟังก์ชันแฮช (และใหญ่) ที่ใช้ในการวิเคราะห์ในทางทฤษฎี
หลุยส์

21

คำตอบนี้สรุปบางส่วนของTAoCPเล่มที่ 3, Ch 6.4

สมมติเรามีชุดของค่า ,ซึ่งเราต้องการที่จะเก็บไว้ในอาร์เรย์ขนาดเมตรเราใช้ฟังก์ชันแฮช ; โดยทั่วไปแล้ว. เราเรียกปัจจัยกดดันของ ที่นี่เราจะถือว่าเป็นธรรมชาติ ; ในสถานการณ์จริงเรามีแม้ว่าและต้อง map ลงไปที่ตัวเองn เมตรต่อชั่วโมง: V [ 0 .. M ) M « | V | α = nVnAmh:V[0..M)M|V|เมตร=Mเมตร«Mเมตรα=nmAm=MmMm

การสังเกตครั้งแรกคือแม้ว่ามีลักษณะเหมือนกัน¹ความน่าจะเป็นของค่าสองค่าที่มีค่าแฮชเดียวกันสูง นี้เป็นหลักเช่นที่น่าอับอายขัดแย้งวันเกิด ดังนั้นโดยทั่วไปเราจะต้องจัดการกับความขัดแย้งและสามารถละทิ้งความหวังของเวลาเข้าถึงกรณีที่เลวร้ายที่สุดO ( 1 )hO(1)

แล้วค่าเฉลี่ยเป็นอย่างไร ให้เราสมมติว่าทุกคีย์จากเกิดขึ้นด้วยความน่าจะเป็นเดียวกัน จำนวนรายการที่ตรวจสอบโดยเฉลี่ย (การค้นหาที่ประสบความสำเร็จ) (การค้นหาไม่สำเร็จ) ขึ้นอยู่กับวิธีการแก้ไขข้อขัดแย้งที่ใช้C S n C U n[0..M)CnSCnU

ผูกมัด

ทุกรายการอาร์เรย์มี (ตัวชี้ไปที่หัว) รายการเชื่อมโยง นี่เป็นความคิดที่ดีเพราะความยาวของรายการที่คาดหวังมีขนาดเล็ก ( ) แม้ว่าความน่าจะเป็นที่จะเกิดการชนนั้นสูง ในท้ายที่สุดเราจะได้ สิ่งนี้สามารถปรับปรุงได้เล็กน้อยโดยการจัดเก็บรายการ (บางส่วนหรือทั้งหมด) ภายในตารางnm

CnS1+α2 and CnU1+α22.

การวัดเชิงเส้น

เมื่อแทรก (resp. ค้นหาค่า)ให้ตรวจสอบตำแหน่ง ตามลำดับนี้จนกระทั่งตำแหน่งว่าง (resp. ) พบ ข้อดีคือเราทำงานในพื้นที่และไม่มีโครงสร้างข้อมูลรอง อย่างไรก็ตามจำนวนเฉลี่ยของการเข้าถึง diverges สำหรับ : อย่างไรก็ตามสำหรับประสิทธิภาพเทียบได้กับการผูกมัด²v

h(v),h(v)1,,0,m1,,h(v)+1
vα1
CnS12(1+11α) and CnU12(1+(11α)2).
α<0.75

การแฮ็ชสองครั้ง

คล้ายกับเส้นตรงแหย่ แต่ขนาดขั้นตอนการค้นหาจะถูกควบคุมโดยฟังก์ชันแฮชที่สองที่เป็น coprime เพื่อMไม่ได้รับการสืบทอดอย่างเป็นทางการ แต่การสังเกตเชิงประจักษ์แนะนำให้ วิธีนี้ได้รับการดัดแปลงโดย Brent; ตัวแปรของเขาทำให้ค่าใช้จ่ายการแทรกเพิ่มขึ้นด้วยการค้นหาที่ถูกกว่าM

CnS1αln(11α) and CnU11α.

โปรดทราบว่าการลบองค์ประกอบออกจากและขยายตารางมีระดับความยากต่างกันสำหรับวิธีการที่เกี่ยวข้อง

บรรทัดล่างคุณต้องเลือกการใช้งานที่ปรับให้เหมาะกับกรณีการใช้งานทั่วไปของคุณ เวลาในการเข้าถึงที่คาดหวังในเป็นไปได้ถ้าไม่รับประกันเสมอ ขึ้นอยู่กับวิธีที่ใช้การรักษา low เป็นสิ่งจำเป็น คุณต้องแลกเปลี่ยนเวลาการเข้าถึง (คาดว่า) กับค่าใช้จ่ายในพื้นที่ ตัวเลือกที่ดีสำหรับก็เป็นศูนย์กลางเช่นกันO(1)αh


1] เนื่องจากโปรแกรมเมอร์ที่ไม่ได้รับการฝึกหัดอย่างโง่เง่าอาจให้ดังนั้นข้อสันนิษฐานใด ๆ เกี่ยวกับคุณภาพของมันจึงเป็นสิ่งที่นำไปปฏิบัติได้จริง 2] สังเกตว่าสิ่งนี้สอดคล้องกับคำแนะนำสำหรับการใช้งานของ Javaอย่างไรh
Hashtable


10

ฟังก์ชันแฮชที่สมบูรณ์แบบสามารถกำหนดเป็นฟังก์ชันหนึ่งต่อหนึ่งจากชุดย่อยของจำนวนเต็มที่\} ถ้าฟังก์ชันแฮชที่สมบูรณ์แบบที่มีอยู่สำหรับข้อมูลและความต้องการการจัดเก็บข้อมูลของคุณคุณสามารถได้รับพฤติกรรม ตัวอย่างเช่นคุณสามารถรับประสิทธิภาพจากตารางแฮชสำหรับงานต่อไปนี้: กำหนดอาร์เรย์ของจำนวนเต็มและชุดของจำนวนเต็มพิจารณาว่ามีสำหรับแต่ละหรือไม่ ขั้นตอนการเตรียมการล่วงหน้าจะเกี่ยวข้องกับการสร้างตารางแฮชในตามด้วยการตรวจสอบแต่ละองค์ประกอบของกับมันในS{0,1,2,...,n}O(1)O(1)lSlxxSO(|l|)SO(|S|)|) พรึบนี้เป็น|) การดำเนินไร้เดียงสาโดยใช้การค้นหาเชิงเส้นอาจจะ ; การใช้การค้นหาแบบไบนารีคุณสามารถทำ (โปรดทราบว่าวิธีนี้เป็นพื้นที่เนื่องจากตารางแฮชต้องจับคู่จำนวนเต็มในกับถังขยะที่แตกต่างกันO(|l|+|S|)O(|l||S|)O(log(|l|)|S|)O(|l|)l

แก้ไข: เพื่อชี้แจงเกี่ยวกับวิธีการสร้างตารางแฮชใน :O(|l|)

รายการมีจำนวนเต็มจากชุด จำกัด , อาจมีซ้ำและU เราต้องการที่จะตรวจสอบว่าอยู่ในลิตรในการทำเช่นนั้นเราคำนวณตารางแฮชล่วงหน้าสำหรับองค์ประกอบของ : ตารางการค้นหา ตารางแฮชจะเข้ารหัสฟังก์ชั่น\} ในการกำหนดเริ่มแรกถือว่าสำหรับทั้งหมด จากนั้นเป็นเส้นตรงสแกนผ่านองค์ประกอบของ , การตั้งค่าtrue สิ่งนี้ใช้เวลาเวลาและlUNSUxSllh:U{true,false}hh(x)=falsexUylh(y)=trueO(|l|)O(|U|) ช่องว่าง

โปรดสังเกตว่าการวิเคราะห์ดั้งเดิมของฉันสันนิษฐานว่ามีองค์ประกอบที่แตกต่างกันอย่างน้อยถ้ามันมีองค์ประกอบที่แตกต่างน้อยกว่า (พูด, ) ความต้องการพื้นที่อาจจะสูงกว่า (แม้ว่าจะไม่เกิน )lO(|U|)O(|1|)O(|U|)

EDIT2: ตารางแฮชสามารถเก็บไว้เป็นอาร์เรย์แบบง่าย ฟังก์ชันแฮชสามารถเป็นฟังก์ชันตัวตนของได้ ขอให้สังเกตว่าฟังก์ชั่นเอกลักษณ์นั้นเป็นฟังก์ชันแฮชที่สมบูรณ์แบบ คือตารางแฮชและเข้ารหัสฟังก์ชันแยกต่างหาก ฉันกำลังเลอะเทอะ / สับสนในบางข้อที่กล่าวมา แต่จะพยายามปรับปรุงในไม่ช้าUh


คุณสามารถขยายส่วนที่คุณทำตารางแฮชในไหม? ฉันสามารถดูวิธีการทำว่าถ้าคุณไม่ต้องกังวลเกี่ยวกับการชน แต่ที่หมายถึงการค้นหาในภายหลังอาจใช้เวลามากกว่าถึง|) O(|l|)O(|S|)O(|l||S|)
Gilles

ฉันไม่เข้าใจความหมายของเอชคุณกำลังกำหนดฟังก์ชั่น แต่ไม่ได้อธิบายว่ามันเป็นตัวแทนอย่างไร คุณเขียน pseudocode สองสามบรรทัดได้ไหม นอกจากนี้ยังมีปัญหาสัญกรณ์; และ bijectiveไปด้วยกันไม่ได้ hh:U{false,true}h
Gilles

@Gilles มันเป็นเพียงการใช้เป็นตารางการค้นหาสำหรับรายการสมาชิก เมื่อคุณมีฟังก์ชั่นแฮชที่สมบูรณ์แบบที่มีค่าผกผันที่รู้จักและราคาถูกแทนที่จะเก็บสิ่งนั้นเองคุณจะต้องเก็บ 1 บิตเท่านั้น (ไม่ว่าจะเพิ่มสิ่งที่มีแฮชที่ไม่ซ้ำกัน) หากการชนกันเป็นไปได้ฉันคิดว่าการทำเช่นนี้เรียกว่าตัวกรอง Bloom แต่ในกรณีใด ๆ ก็สามารถให้คำถามที่ชัดเจนเกี่ยวกับการเป็นสมาชิกซึ่งไม่มีประโยชน์ในหลาย ๆ สถานการณ์
Patrick87

9

ฟังก์ชันแฮชที่สมบูรณ์แบบจะส่งผลให้ค้นหาตัวพิมพ์เล็กที่สุดO(1)

ยิ่งไปกว่านั้นหากจำนวนการชนสูงสุดที่เป็นไปได้คือค้นหาตารางแฮชอาจกล่าวได้ว่าเป็นในกรณีที่เลวร้ายที่สุด หากจำนวนการชนที่คาดไว้คือการค้นหาตารางแฮชสามารถกล่าวได้ว่าเป็นในกรณีทั่วไปO ( 1 ) O ( 1 ) O ( 1 )O(1)O(1)O(1)O(1)


ฟังก์ชันแฮชที่สมบูรณ์แบบจะสมบูรณ์แบบ แต่ฉันจะรับได้อย่างไร ฉันต้องเสียค่าใช้จ่ายเท่าไหร่ และฉันจะทราบได้อย่างไรว่าจำนวนการชนสูงสุดหรือที่คาดไว้คือเท่าใด
Gilles

2
@Gilles ฟังก์ชั่นแฮชที่สมบูรณ์แบบคือฟังก์ชั่นใด ๆ ที่จะสร้างแฮชที่เป็นเอกลักษณ์สำหรับอินพุตที่เป็นไปได้ทั้งหมด หากอินพุตที่เป็นไปได้ของคุณมี จำกัด (และไม่ซ้ำใคร) สิ่งนี้ง่ายต่อการทำ
Rafe Kettler

1
@RafeKettler อินพุตของฉันมักจะเป็นสตริงหรือโครงสร้างข้อมูลแบบผสมและฉันมักจะเพิ่มและลบรายการตามที่ข้อมูลของฉันวิวัฒนาการ ฉันจะทำให้แฮชที่สมบูรณ์แบบสำหรับสิ่งนี้ได้อย่างไร
Gilles

4
ใช่ แต่นั่นคือประเด็น ฟังก์ชันแฮชที่สมบูรณ์แบบที่กำหนดขึ้นได้จะไม่มีอยู่หากโดเมนมีขนาดใหญ่กว่าช่วง
Suresh

@Suresh: หากคุณได้รับอนุญาตให้เลือกฟังก์ชั่นแฮชใหม่และเพิ่มขนาดของตารางเมื่อใดก็ตามที่มีการชนกันคุณสามารถค้นหาฟังก์ชันแฮช (กำหนดขึ้น) ได้เสมอ - สำหรับข้อมูลที่มีอยู่ในตารางแล้ว รายการที่คุณพยายามแทรก - ไม่มีการชน (คือ "สมบูรณ์แบบ") นั่นคือเหตุผลที่การแฮชแบบสมบูรณ์แบบไดนามิกเป็นระยะเลือกฟังก์ชันแฮชแบบสุ่มใหม่
เดวิดแครี
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.