ฉันพยายามที่จะเข้าใจตารางแฮช - บางคนสามารถอธิบายให้ฉัน - อย่างชัดเจน?


25

ฉันต้องการเข้าใจการใช้งานที่ถูกต้องและการนำไปใช้งานของตารางแฮชใน php (ขออภัย)

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

ดังนั้นใครบางคนสามารถอธิบายให้ฉันรู้วิธีการใช้ตารางแฮชใน php (สมมุติว่าเป็นอาเรย์แบบเชื่อมโยง) และที่สำคัญกว่านั้นคือวิธีเข้าถึงค่า 'ด้วยแฮช' และสิ่งที่จริงหมายถึงอะไร

คำตอบ:


37

ภาพรวมตารางแฮชแบบง่าย

ในฐานะผู้ทบทวนตารางแฮชเป็นวิธีการจัดเก็บค่าภายใต้คีย์เฉพาะในโครงสร้างข้อมูล ตัวอย่างเช่นฉันสามารถเก็บค่า"a"ไว้ใต้คีย์1แล้วเรียกคืนได้ในภายหลังโดยค้นหาคีย์1ในตารางแฮช

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

---------------------------------
|   |   |   |   |   |   |   |   |
---------------------------------
  0   1   2   3   4   5   6   7  

ฟังก์ชั่นแฮช

ฟังก์ชันแฮชให้ดัชนีเกี่ยวกับสถานที่จัดเก็บค่าของคุณ ฟังก์ชั่นกัญชาสวยเรียบง่ายสำหรับตารางนี้จะเพิ่ม 1 ถึงค่าที่คุณต้องการในการจัดเก็บและจากนั้นmodมัน 8 (ขนาดตาราง) ในคำอื่น ๆ ฟังก์ชั่นแฮชของคุณคือ(n+1)%8ที่ซึ่งnเป็นจำนวนเต็มที่คุณต้องการจัดเก็บ

แทรก

หากคุณต้องการแทรกค่าลงในตารางแฮชนี้คุณจะเรียกใช้ฟังก์ชันแฮช (ในกรณีนี้(n+1)%8) กับค่าที่คุณต้องการแทรกเพื่อให้ดัชนี ตัวอย่างเช่นถ้าเราต้องการที่จะใส่ 14 เราจะเรียก(14 + 1) % 8และได้รับดัชนีดังนั้นเราจึงต้องการใส่ค่าในดัชนี77

---------------------------------
|   |   |   |   |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

ในทำนองเดียวกันเราสามารถแทรก 33, 82 และ 191 ดังนี้:

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

การชนกัน

แต่จะเกิดอะไรขึ้นถ้าเราพยายามแทรกบางสิ่งที่จะชนกับรายการ 2 ควรอยู่ในดัชนี3แต่ดำเนินการโดย 82 มีหลายวิธีในการแก้ปัญหานี้วิธีที่ง่ายที่สุดคือเรียกฟังก์ชันแฮชของเราซ้ำแล้วซ้ำอีกจนกว่าเราจะหาพื้นที่ว่าง

ดังนั้นตรรกะมีดังนี้

  1. (2 + 1)% 8 = 3
  2. ดัชนี3เต็ม
  3. เสียบ3กลับเข้าสู่ฟังก์ชันแฮชของเรา ( 3 + 1)% 8 = 4ซึ่งว่างเปล่า
  4. วางค่าของเราเป็นดัชนีที่ 4

ตอนนี้ตารางแฮชที่มีลักษณะเช่นนี้มีมูลค่า 2 4เก็บไว้ที่ดัชนี

---------------------------------
|191|   |33 |82 |2  |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

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

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

ถ้าคุณจำ(2+1)%8ทำให้เรามีดัชนี3ซึ่งจะได้รับการ หากคุณไม่ต้องการให้ตารางแฮชเติมคุณสามารถใช้ดัชนีแต่ละตารางเป็นรายการที่ลิงก์และผนวกเข้ากับรายการที่ดัชนีนั้น ดังนั้นแทนที่จะเรียกฟังก์ชันแฮชอีกครั้งเราจะเพียงผนวกไปยังรายการที่ดัชนี3:

            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

รายการนี้สามารถขยายได้มากเท่าที่หน่วยความจำจะอนุญาต ฉันสามารถใส่ 18 และมันจะถูกผนวกเข้ากับ 2:

            -----
            |18 |
            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

การค้นหา

ค้นหาค่าในตารางแฮชของคุณอย่างรวดเร็วเนื่องจากตารางแฮชของคุณมีขนาดใหญ่มาก คุณเพียงแค่เรียกฟังก์ชันแฮชของคุณและรับดัชนี สมมติว่าคุณต้องการดูว่า 82 อยู่ในตารางของคุณหรือไม่ ฟังก์ชั่นการค้นหาจะเรียก(82+1)%8= 3และดูรายการในดัชนี3และส่งคืนให้คุณ หากคุณค้นหา 16 ฟังก์ชันการค้นหาจะค้นหาในดัชนี1และดูว่าไม่มีอยู่

การค้นหาจำเป็นต้องจัดการการชนเช่นกัน!

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

สรุป

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


2
ASCII art FTW!
Anto

2
คำตอบที่ดี มันอาจจะคุ้มค่าที่จะกล่าวถึงว่าวิธีการที่ดัชนีแต่ละรายการเชื่อมโยงเรียกว่าการผูกมัด
alexn

+1 คำตอบที่ยอดเยี่ยมโผล่ออกมาเกือบทุกข้อสงสัยปิดหัวของฉัน ต้องถามคำถามอีกหนึ่งข้อ การใช้งานทุกครั้งใช้การแฮชเพื่อเก็บจำนวนเต็มหรือไม่ หรือใช้สำหรับกรณีเฉพาะ? ถ้าใช่แล้วกรณีเหล่านั้นคืออะไร?
0Decimal0

@PHIfounder ฉันไม่แน่ใจว่าฉันเข้าใจคำถามของคุณครบถ้วนหรือไม่ แต่ฟังก์ชันแฮชที่ทำกับคีย์นั้นได้รับการออกแบบให้เป็นแบบทั่วไปไม่ใช่เพียงแค่นำไปใช้กับประเภทข้อมูลเฉพาะเช่นจำนวนเต็ม หากเรากำลังพูดถึงรหัส C ตารางแฮชอาจได้รับการออกแบบให้ยอมรับ (เป็นโมฆะ *) สำหรับคีย์และค่าและทำการคำนวณแฮชบนค่าตัวชี้ของคีย์
Jeff

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

7

ลองนึกภาพห้องสมุดที่มีหนังสือหลายพันเล่ม คุณต้องจัดระเบียบหนังสือเพื่อให้คุณสามารถค้นหาหนังสือแต่ละเล่มได้โดยเร็วที่สุด

วิธีหนึ่งในการทำเช่นนี้คือการจัดเรียงหนังสือตามลำดับตัวอักษร หากชื่อของคุณเริ่มต้นด้วยคำว่า "G" คุณจะพบพื้นที่ "G" จากนั้นมองหาตัวอักษรตัวที่สองพูดว่า "ö" จากนั้น "d", "e", "e", "l", จำกัด การค้นหาของคุณให้แคบลง จนกว่าคุณจะพบหนังสือ อย่างไรก็ตามสิ่งนี้อาจใช้เวลานานและยิ่งกว่านั้นเมื่อหนังสือใหม่มาถึงคุณบางครั้งจำเป็นต้องจัดโครงสร้างใหม่เพื่อให้มีที่ว่างสำหรับการมาถึงใหม่

นั่นคือการค้นหาแบบไบนารี ดี.

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

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

ตารางแฮชมีข้อ จำกัด และการปรับเปลี่ยน (rehashing / resizing) ซึ่งทำให้การค้นหาแบบไบนารี่รอบ ๆ เป็นคู่แข่ง ไม่ใช่ขาวดำทั้งหมดโดยคำนึงถึงวิธีการที่ดีกว่า แต่นั่นเป็นเรื่องที่แตกต่าง

PS ขออภัยที่ไม่ตอบคำถามของคุณโดยตรง (เขียนตารางแฮชใน PHP) แต่นั่นเป็นรายละเอียดและเรียกว่า "โปรแกรม";)


2
ฉันชอบคำอธิบายที่ไม่เกี่ยวข้องกับคอมพิวเตอร์สำหรับปัญหาที่เกี่ยวข้องกับคอมพิวเตอร์ +1
gablin

1

ตารางแฮชใน PHP เท่าที่ความรู้ของฉันถูกนำไปใช้งานผ่าน:

$my_hash = array(
    1 => "Bob",
    2 => "Alice",
    3 => "Jack"
);

จากนั้นคุณสามารถเข้าถึงข้อมูลผ่านการโทรเช่น:

echo $my_hash[2]; // Will echo "Alice"

คุณใช้ฟังก์ชัน foreach () เพื่อทำซ้ำเนื้อหาของอาร์เรย์

วิธีที่ดีที่สุดในการทำความเข้าใจกับตารางแฮชคือการอ่านสิ่งที่ต้องการhttp://en.wikipedia.org/wiki/Hash_tableแต่โดยทั่วไปแล้วจะเดือดลงไปที่นี่: ด้านซ้ายมือของทุกบรรทัดในการเรียก array () เป็นกุญแจ . กุญแจเหล่านี้จะถูกนำมาใช้ในการคำนวณแฮชและผลลัพธ์จะเป็นแฮช คุณอาจเคยเห็นแฮ็ก MD5 หรือ SHA มาก่อนมันค่อนข้างคล้ายกับสิ่งนี้ ส่วนเฉพาะของแฮชนี้โดยทั่วไปคืออักขระ X ตัวแรก แต่บางครั้งแฮชแบบสมบูรณ์จะถูกใช้เพื่อระบุสิ่งที่เรียกว่า 'buckets' ซึ่งเป็นพื้นที่เก็บข้อมูลสำหรับค่า (ด้านขวามือ)

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

ฉันหวังว่าสิ่งนี้จะให้พื้นหลัง แต่โปรดลองอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้หากคุณสนใจ คำอธิบายของฉันเป็นพื้นฐานมากและฉันแน่ใจว่ามีรูเพียงพอในนั้น แต่มันก็เพียงพอสำหรับคำอธิบายอย่างรวดเร็ว

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