Menu
Coddy logo textTech

Hash Map (מפת גיבוב)

עודכן לאחרונה

Hash map שומר זוגות מפתח-ערך ומאפשר למצוא ערך לפי המפתח שלו ב-O(1) בממוצע. הוא עובד בדיוק כמו טבלת גיבוב, אבל כל רשומה בדלי נושאת גם מפתח וגם את הערך המשויך לו. כדי לשמור או לשלוף זוג, מגבבים את המפתח לאינדקס של דלי, ואז סורקים את השרשרת של הדלי כדי למצוא את המפתח המתאים. לחצו על הפעלה למעלה כדי לראות זוגות מוצבים לפי דלי מגובב וערך נשלף לפי המפתח שלו.

זה המבנה שמאחורי dict של Python, HashMap של Java ו-Map/אובייקטים של JavaScript. התנגשויות מטופלות באותה דרך כמו בטבלת גיבוב, כאן בעזרת שרשור נפרד, ולכן הביצועים תלויים בפונקציית גיבוב טובה ובמקדם עומס נמוך.

סיבוכיות זמן

פעולהממוצעהמקרה הגרוע
Put (הכנסה או עדכון)O(1)O(n)
Get (חיפוש)O(1)O(n)
מחיקהO(1)O(n)
זיכרוןO(n)O(n)

Hash map בשפות נפוצות

שפהטיפוס
Pythondict
JavaHashMap
JavaScriptMap / object
C++std::unordered_map
Gomap

דוגמה מפורטת

הכנסת הזוגות ("cat", 3), ("dog", 5), ("cat", 9), ("emu", 7) למפה עם 8 דליים, בעזרת hash(key) % 8. נניח ש-hash("cat") % 8 = 2, hash("dog") % 8 = 5, hash("emu") % 8 = 2:

צעדמבנהפעולה
Put ("cat", 3)דלי 2: [("cat", 3)]מגובב לדלי 2; השרשרת ריקה, ולכן מוסיפים את הזוג.
Put ("dog", 5)דלי 2: [("cat", 3)], דלי 5: [("dog", 5)]מגובב לדלי 5; השרשרת ריקה, ולכן מוסיפים את הזוג.
Put ("cat", 9)דלי 2: [("cat", 9)], דלי 5: [("dog", 5)]מגובב לדלי 2; המפתח "cat" כבר בשרשרת, ולכן מעדכנים את הערך שלו ל-9.
Put ("emu", 7)דלי 2: [("cat", 9), ("emu", 7)], דלי 5: [("dog", 5)]מגובב לדלי 2; מתנגש עם "cat", המפתח לא נמצא, ולכן מוסיפים את הזוג.
Get "emu"דלי 2: [("cat", 9), ("emu", 7)]מגובב לדלי 2; סורקים את השרשרת, מדלגים על "cat", מוצאים את "emu" ומחזירים 7.

מתי להשתמש ב-hash map

השתמשו בו כאשרהימנעו ממנו כאשר
אתם צריכים חיפוש, הכנסה ומחיקה של O(1) בממוצע לפי מפתח מדויק.אתם צריכים מפתחות בסדר ממוין או שאילתות טווח: השתמשו ב-BST מאוזן או במפה ממוינת.
המפתחות ניתנים לגיבוב והשוויון מוגדר היטב (מחרוזות, מספרים שלמים, tuples).המפתחות ניתנים לשינוי ויכולים להשתנות אחרי ההכנסה, מה שמשבש את הדלי שלהם.
אתם סופרים, מסירים כפילויות, שומרים במטמון או מאנדקסים לפי מזהה.אתם צריכים הבטחות של O(log n) במקרה הגרוע ולא חסמים ממוצעים לשיעורין.
סדר המעבר לא משנה, או שמפה ששומרת על סדר ההכנסה מספיקה.הזיכרון מוגבל מאוד: דליים, מרווח למקדם העומס ומצביעים מוסיפים תקורה.

קוד Hash Map

מימוש נקי של Hash Map שאפשר להריץ, ב-Python, JavaScript, Java, C++, C. בחרו שפה, העתיקו את הקוד, או פתחו אותו טעון מראש בעורך האונליין של Coddy.

קוד Hash Map ב-Python

Python
1# Python's built-in dict is a hash map: O(1) average2# insert, lookup, and delete.3inventory = {"apple": 3, "banana": 7}4
5# Insert and update6inventory["cherry"] = 57inventory["apple"] += 28
9# Lookup, with .get for a safe default on missing keys10print("apple: ", inventory["apple"])11print("mango: ", inventory.get("mango", 0))12
13# Membership test and delete14print("banana in stock:", "banana" in inventory)15del inventory["banana"]16print("banana in stock:", "banana" in inventory)17
18# Iterate over key-value pairs19for fruit, count in sorted(inventory.items()):20    print(f"{fruit}: {count}")21
22# Classic hash map use case: counting frequencies23words = "the quick brown fox jumps over the lazy dog the end".split()24freq = {}25for word in words:26    freq[word] = freq.get(word, 0) + 127
28print("Occurrences of the:", freq["the"])29print("Most common word:  ", max(freq, key=freq.get))
להריץ את הקוד הזה בעורך ה-Python אונליין

שאלות נפוצות על hash map

מה ההבדל בין hash map לטבלת גיבוב (hash table)?
בעיקרון זה אותו מבנה: מערך של דליים שניגשים אליהם לפי גיבוב של המפתח. בשימוש נפוץ, "hash table" מתייחס לעתים קרובות לקבוצה של מפתחות או לטכניקה הכללית, ואילו "hash map" מדגיש שמירה של זוגות מפתח-ערך. חלק מהשפות מבחינות גם לפי בטיחות בריבוי תהליכונים (למשל Hashtable מול HashMap ב-Java), אבל האלגוריתם הבסיסי זהה.
מהי סיבוכיות הזמן של hash map?
Put, get ומחיקה הם O(1) בממוצע עם פונקציית גיבוב טובה ומקדם עומס נמוך. במקרה הפתולוגי שבו כל המפתחות מתנגשים לאותו דלי, הם מידרדרים ל-O(n), ולכן שינוי גודל וגיבוב טוב חשובים.
איך hash map מטפל בשני מפתחות שמגובבים לאותו דלי?
הוא פותר את ההתנגשות. ההדמיה הזו משתמשת בשרשור נפרד: כל דלי מחזיק רשימה קטנה, וזוג חדש שהמפתח שלו מגובב לשם מתווסף לרשימה הזו. בחיפוש, המפה סורקת את השרשרת הקצרה עד שהיא מוצאת את המפתח המתאים. הטכניקה החלופית היא מיעון פתוח, שמחפש תא אחר במערך.
Hash map או עץ חיפוש בינארי: במה להשתמש?
השתמשו ב-hash map כשצריך רק חיפוש לפי מפתח מדויק ורוצים פעולות של O(1) בממוצע. השתמשו בעץ חיפוש בינארי מאוזן (כמו TreeMap או std::map) כשצריך מפתחות בסדר ממוין, שאילתות טווח או חיפוש קודם ועוקב, שעולים O(log n). ה-BST מוותר על מעט מהירות בתמורה להבטחות סדר ש-hash map לא יכול לספק.
מהו מקדם העומס ולמה הוא גורם לשינוי גודל?
מקדם העומס הוא היחס בין מספר הרשומות השמורות למספר הדליים. כשהוא עולה, השרשראות מתארכות והחיפושים הממוצעים מאטים, ולכן רוב המימושים משנים גודל (בדרך כלל מכפילים את מספר הדליים ומגבבים הכל מחדש) ברגע שהוא עובר סף כמו 0.75. שינוי גודל הוא O(n) אבל נדיר, ולכן העלות מתפזרת ושומרת על פעולות ממוצעות של O(1).
האם אפשר להשתמש באובייקט שניתן לשינוי, כמו רשימה, כמפתח ב-hash map?
בדרך כלל לא. מפתחות חייבים להיות ניתנים לגיבוב, והגיבוב שלהם חייב להישאר קבוע כל עוד הם במפה. למשל, Python זורקת TypeError: unhashable type עבור list. אם משנים מפתח אחרי שהוכנס, הגיבוב שלו משתנה והמפה כבר לא מוצאת אותו בדלי הנכון, והרשומה הולכת לאיבוד בשקט. השתמשו במפתחות שאינם ניתנים לשינוי, כמו מחרוזות, מספרים או tuples.
איור של שפות התכנות ב-Coddy

לשלוט באלגוריתמים עם Coddy

להתחיל