เป็นไปได้หรือไม่ที่จะใช้ตารางแฮชแบบกระจายโดยไม่ต้องใช้ตัวดำเนินการ%


11

ฉันต้องการใช้ตารางแฮชที่กระจายอย่างรวดเร็วใน C # ฉันมีปัญหาในการเลือกฟังก์ชั่นแฮช จำกัด ของฉันที่ใช้รหัสแฮชตามอำเภอใจและ "จำกัด " มันเพื่อให้สามารถใช้สร้างดัชนีถังได้ มีสองตัวเลือกที่ฉันเห็น:

  • ในมือข้างหนึ่งคุณสามารถตรวจสอบให้แน่ใจว่าถังของคุณมีองค์ประกอบจำนวนมากเสมอและเพื่อ จำกัด การแฮชคุณเพียงแค่ปรับค่าตามจำนวนถัง นี่คือความจริงแล้วพจนานุกรมของ. NET ทำอะไร ปัญหาของวิธีนี้คือการใช้% ช้ามากเมื่อเทียบกับการปฏิบัติการอื่น ถ้าคุณมองไปที่ตารางการเรียนการสอน Agner ตัดหมอก , idiv(ซึ่งเป็นรหัสการชุมนุมที่ได้รับการสร้างขึ้นสำหรับ%) มีการเรียนการสอนแฝง ~ 25 รอบสำหรับโปรเซสเซอร์ Intel ใหม่ เปรียบเทียบนี้เพื่อรอบ 3 mulหรือ 1 สำหรับ Ops บิตเช่นand, หรือorxor

  • ในทางกลับกันคุณสามารถมีจำนวนของถังเสมอได้ 2 คุณยังจะต้องคำนวณโมดูลัสของแฮชดังนั้นคุณจึงไม่ได้พยายามทำดัชนีนอกอาร์เรย์ แต่คราวนี้มันจะมีราคาไม่แพง . เนื่องจากกำลังของ 2 % Nเป็นเพียง& (N - 1)ข้อ จำกัด จึงลดลงเป็นการดำเนินการปิดบังซึ่งใช้เวลาเพียง 1-2 รอบเท่านั้น นี้จะกระทำโดยsparsehash ของ Google ข้อเสียของสิ่งนี้คือเรากำลังไว้ใจผู้ใช้เพื่อให้แฮชดี การปิดบังแฮชจะตัดส่วนของแฮชออกเป็นส่วนใหญ่ดังนั้นเราจะไม่คำนึงถึงบิตของแฮชทั้งหมดอีกต่อไป หากแฮชของผู้ใช้มีการกระจายอย่างไม่สม่ำเสมอตัวอย่างเช่นบิตที่สูงกว่าจะถูกเติมเต็มหรือบิตที่ต่ำกว่านั้นจะเท่ากันเสมอวิธีการนี้จะมีอัตราการชนที่สูงกว่ามาก

ฉันกำลังมองหาอัลกอริทึมที่ฉันสามารถใช้ได้ซึ่งมีทั้งสองอย่างที่ดีที่สุดในโลก: มันต้องคำนึงถึงบิตทั้งหมดของการแฮชและยังเร็วกว่าการใช้% ไม่จำเป็นต้องเป็นโมดูลัสเพียงบางสิ่งที่รับประกันว่าจะอยู่ในช่วง0..N-1(โดยที่ N คือความยาวของที่เก็บข้อมูล) และมีการแจกแจงที่สม่ำเสมอสำหรับช่องทั้งหมด อัลกอริทึมดังกล่าวมีอยู่จริงหรือไม่?

ขอบคุณสำหรับการช่วยเหลือ.


1
เงยหน้าขึ้นมองผลหิมะถล่มเช่นเดียวกับคำอธิบายในmurmurhash3 (smhasher) อย่างไรก็ตามประเด็นพื้นฐานในคำถามของคุณไม่ได้รับการแก้ไขด้วยการนำฟังก์ชันแฮชที่ดีกว่ามาใช้ แต่เป็นคำถามเกี่ยวกับสาเหตุที่ผู้ใช้ไม่ได้ใช้ฟังก์ชั่นแฮชที่ดีกว่าเดิมตั้งแต่แรกและเรียกร้องให้มีมาตรการตอบโต้


สำหรับ modulo ที่รวดเร็ว(2^N +/- 1)ดูstackoverflow.com/questions/763137/…
rwong

@rwong ฉันขอโทษ แต่ฉันไม่แน่ใจว่าความคิดเห็นของคุณเกี่ยวข้องกับโพสต์ของฉันอย่างไร ฉันไม่ได้ควบคุมแฮชที่ผู้ใช้จัดหาดังนั้นฉันจึงไม่ต้องการฟังก์ชั่นแฮชที่ดีขึ้น ฉันไม่เข้าใจสิ่งที่คุณหมายถึงโดย "ผู้ใช้ที่ขี้เกียจอย่างไม่ประสงค์ดี"
James Ko

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

คำตอบ:


9

การใช้งานตารางแฮชที่ทันสมัยไม่ใช้ฟังก์ชันโมดูโล พวกเขามักจะใช้พลังของตารางขนาดสองและตัดออกบิตที่ไม่จำเป็น ฟังก์ชันแฮชที่เหมาะจะอนุญาต การใช้โมดูโลรวมกับขนาดตารางจำนวนเฉพาะเกิดขึ้นในวันที่ฟังก์ชันแฮชโดยทั่วไปไม่ดีเนื่องจากมักจะอยู่ในการพัฒนา. net ผมขอแนะนำให้อ่านเกี่ยวกับSipHash , ฟังก์ชั่นที่ทันสมัยกัญชาแล้วอ่านเกี่ยวกับฟังก์ชั่นที่ทันสมัยอื่น ๆ บางอย่างเช่นxxHash

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

  • การห่อหุ้มของสถานะแฮชในโครงสร้างหรือคลาส
  • ฟังก์ชัน hash "เพิ่ม" ซึ่งเพิ่มข้อมูลใหม่ให้กับสถานะแฮช (เพิ่มอาร์เรย์ไบต์หรือสองครั้งเป็นต้น)
  • ฟังก์ชัน "finalize" hash เพื่อสร้างหิมะถล่ม
  • การห่อหุ้มผลลัพธ์แฮช - ใน. net คุณจะได้รับหนึ่งทางเลือกซึ่งเป็นจำนวนเต็ม 32 บิตที่เซ็นชื่อ

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ฟังก์ชันแฮชผลลัพธ์เป็นดัชนีตารางแฮชโปรดดูคำจำกัดความของรูปแบบสากลของการแปลงแป้นพิมพ์ในเอกสารนี้: การแฮชแบบสากลที่เร็วขึ้น 64 บิตโดยใช้การคูณแบบพกพา


3

หากต้องการใช้ AND ในขณะที่ยังคงเก็บบิตทั้งหมดไว้ให้ใช้ XOR ด้วย

ตัวอย่างเช่นtemp = (hash & 0xFFFF) ^ ( hash >> 16); index = (temp & 0xFF) ^ (temp >> 8);.

ตัวอย่างนี้ไม่มีแบบโมดูโลและ 32 บิตของhashผลกระทบที่ index8 อย่างไรก็ตามไม่ว่าจะเร็วกว่า DIV หรือไม่นั้นขึ้นอยู่กับปัจจัยหลายอย่างและช้ากว่า DIV ในบางกรณี (เช่นแฮชขนาดใหญ่และดัชนีเล็ก ๆ )


นี้เสมอไปจะเร็วกว่า DIV / IDIV แต่ฉันไม่คิดว่ามันตอบคำถามของฉันจะอยู่ในช่วงindex [0..255]ฉันต้องการบางสิ่งบางอย่างในช่วง[0..n-1]ที่nจำนวนถังอยู่ที่ไหน
James Ko

@JamesKo แต่ถ้าคุณใช้พจนานุกรมคุณยังสามารถควบคุมจำนวนของถังได้ (ในระดับหนึ่ง) ดังนั้นแทนที่จะเป็นจำนวนเฉพาะคุณสามารถเลือกกำลังสอง (ไม่ว่าการทำเช่นนั้นจะเป็นความคิดที่ดีจริง ๆ ฉันไม่สามารถบอกคุณได้)
svick

@svick สำหรับพลังของ 2 เราสามารถทำการดำเนินการรูปแบบง่าย ๆ ดังที่ได้กล่าวไว้ในคำถามฉันกำลังมองหาวิธีที่ประหยัดในการทำสิ่งเหล่านี้กับตัวเลขจำนวนมากดังนั้นแม้จะมีแฮชที่กระจายไม่ดีก็ตาม
James Ko

1

คุณสามารถใช้ประโยชน์จากความจริงที่ว่าจำนวนเต็มจำนวนมากมีการผกผันการคูณแบบแยกส่วน ดูบทความนี้ คุณมีข้อ จำกัด ข้อใดข้อหนึ่งโดยกำหนดดัชนีถังของคุณและโมดูลัส 2 ^ n ซึ่งค่อนข้างสำคัญโดยธรรมชาติ

บทความนี้อธิบายถึงอัลกอริทึมในการค้นหาจำนวนที่คูณด้วยจำนวนนั้นและการละเว้นการโอเวอร์โฟลว์จะให้ผลลัพธ์เช่นเดียวกับถ้าคุณหารด้วยขนาดดัชนีที่ฝากข้อมูล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.