טבלת גיבוב

מבנה טבלת הגיבוב

טבלת הגיבוב מורכבת ממערך, והתאים שבו מפנים לרשומה הרצויה. כדי להגיע אל התא הרצוי נעשה שימוש בפונקציה שנקראת פונקציית גיבוב או פונקציית ערבול. הפונקציה מקבלת את המפתח של הרשומה ומחזירה את מספר התא שמפנה אל הרשומה אם היא קיימת. הפונקציה משמשת לחיפוש רשומה רצויה, מציאת מקום מתאים עבור הכנסה של רשומה חדשה, ומציאת המקום של רשומה שצריך למחוק.
כדוגמה לטבלת גיבוב פשוטה נוכל לקחת מפעל קטן בעל 1000 עובדים שבו רוצים לשמור רשומות המכילות את פרטי העובדים והגישה לרשומות תהיה לפי מספר עובד בן 3 ספרות (000-999). כדי לבנות טבלת גיבוב מתאימה, נוכל להשתמש במערך בעל אלף תאים ונבחר פונקציית גיבוב פשוטה שעבור כל מספר עובד, מחזירה את המספר עצמו (פונקציית הזהות) ולמעשה מצביעה על כך שאת המידע על העובד שמספרו X נוכל להשיג בתא מספר X. בדוגמה הזאת ביצענו מיעון ישיר - השתמשנו ב"פונקציה חד-חד-ערכית", כלומר, לא קיים יותר ממספר עובד אחד שיופנה לתא מסוים.

בעיית ההתנגשות

פעמים רבות לא ניתן להשתמש ב"פונקציה חד-חד-ערכית", למשל, אם היינו רוצים לגשת לרשומות עובדים בעזרת מספר תעודת הזהות שלהם ושימוש בפונקציית הזהות, אז היינו צריכים להקצות מערך של מיליארד(!) תאים כדי שיתאים לטווח של הפונקציה. הבעיה נוצרת כאשר מספר המפתחות האפשריים, גדול בהרבה מאשר מספר הרשומות שיהיו בטבלת הגיבוב. כדי להתמודד עם הבעיה משתמשים גם בפונקציות שאינן חד-חד-ערכיות, מה שיאפשר שימוש במערך קטן יותר אך יגרור בעיה נוספת של התנגשויות, כלומר, הפונקציה מחזירה עבור הרשומה, מספר תא שמתאים גם לרשומה אחרת.

טבלה פתוחה וסגורה

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

פעולת חיפוש

כדי לחפש ערך בטבלה משתמשים בפונקציית הגיבוב שמקבלת כמשתנה את המפתח של הרשומה המבוקשת כאשר המטרה היא שהערך שהפונקציה מחזירה יוביל אותנו אל הרשומה.
כאשר מדובר על טבלה פתוחה, פעולת החיפוש צריכה לטפל בבעיית ההתנגשות. כלומר, המפתח הוביל אותנו אל רשומה שלא מתאימה אליו. בעיה זו נפתרת לרוב על ידי משתנה נוסף שהפונקציה מקבלת והוא מקבל ערך חדש עבור כל התנגשות נוספת בחיפוש הנוכחי. פונקציית הגיבוב מתייחסת אל המשתנה הזה כאשר היא מחזירה את הערך ותחזיר ערך חדש אחרי כל התנגשות. החיפוש נגמר כאשר מצאנו את הרשומה המתאימה או כשמגיעים לתא שלא הפנה לשום ערך. בשימוש בשיטה הזאת יכולה להתקיים בעיה כאשר מוחקים מהטבלה את אחת הרשומות שהיא גם אחת מההתנגשויות בחיפוש אחר רשומה נוספת. בפעולת החיפוש נקבל את הרושם שהגענו לתא שלא הפנה לשום רשומה ולכן נפסיק את החיפוש. הפתרון לבעיה הוא באמצעות משתנה שישמור עבור כל תא בטבלה אם הוא הפנה אל רשומה ובזמן החיפוש נבדוק באמצעות המשתנה אם התא "אוכלס" בעבר.
עבור פונקציית גיבוב טובה, סיבוכיות הזמן תהיה תלויה במספר ההתנגשויות בזמן חיפוש ערך ותהיה גבוהה יותר ככל שמספר הרשומות בטבלה, מתקרב לגודל המערך (מסומן "B<<n" כאשר B - גודל המערך, n - מספר הרשומות בפועל במערך). הסיבוכיות תהיה תלויה גם בכמות הרשומות שהוכנסו לטבלה אפילו אם הן כבר לא נמצאות בה כיוון שהרבה תאים יסומנו כתאים ש"אוכלסו". כאשר כמות הרשומות אינה גבוהה, מספר ההתנגשויות צפוי להיות בודד ולכן סיבוכיות החיפוש תהיה במקרה הממוצע . במקרה הגרוע של הרבה התנגשויות הסיבוכיות תהיה .
בטבלה סגורה בעיית ההתנגשות נפתרת על ידי מבנה נתונים נוסף שאליו התא בטבלה מפנה. החיפוש נעשה על ידי שימוש בפונקציית שמחזירה אינדקס במערך ולאחר מכן בפונקציית החיפוש של מבנה הנתונים שאליו מפנה האינדקס.
עבור פונקציית גיבוב טובה, כאשר כמות הרשומות באותו סדר גודל של מספר התאים במערך (מסומן "B~n"), סיבוכיות החיפוש תהיה במקרה הממוצע  כיוון שבכל מבנה נתונים יהיה בממוצע מספר בודד של רשומות. במקרה הגרוע, הסיבוכיות תהיה כמו הסיבוכיות במקרה הגרוע של מבנה הנתונים בו משתמשים.

פעולת הכנסה

הכנסת רשומה לטבלה מתבצעת בעזרת מציאת מקום מתאים לרשומה באופן דומה לחיפוש רגיל בטבלה והכנסת הרשומה במקום שנמצא.
עבור הכנסה בטבלה פתוחה, גם כאשר מוצאים תא שהיה בעבר מאוכלס, מכניסים לתוכו את הרשומה. סיבוכיות ההכנסה עבור פונקציה טובה וטבלה שמספר הרשומות בה קטן באופן משמעותי ממספר התאים, תהיה במקרה הממוצע . במקרה הגרוע של הרבה התנגשויות הסיבוכיות תהיה .
בטבלה סגורה ההכנסה מתבצעת באמצעות מציאת המקום המתאים בטבלה על ידי פונקציית הגיבוב ואז שימוש בפונקציית ההכנסה של מבנה הנתונים הנוסף אתו עובדים. סיבוכיות ההכנסה תהיה כמו בחיפוש.

פעולת מחיקה

גם הוצאת רשומה מטבלת הגיבוב דומה לחיפוש.
בטבלה פתוחה, מבצעים חיפוש של הרשומה וכאשר מוצאים אותה, מוחקים אותה ומסמנים את התא כתא ש"אוכלס". סיבוכיות המחיקה תהיה כמו סיבוכיות החיפוש.
בטבלה סגורה המחיקה מתבצעת באמצעות מציאת המקום המתאים בטבלה על ידי פונקציית הגיבוב ואז שימוש בפונקציית ההוצאה של מבנה הנתונים הנוסף אתו עובדים. סיבוכיות המחיקה תהיה כמו סיבוכיות החיפוש.

שימושים לטבלאות גיבוב

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