Presentation is loading. Please wait.

Presentation is loading. Please wait.

ערבול (Hashing) חומר קריאה לשיעור זה:

Similar presentations


Presentation on theme: "ערבול (Hashing) חומר קריאה לשיעור זה:"— Presentation transcript:

1 ערבול (Hashing) חומר קריאה לשיעור זה:
Lecture7 of Geiger & Itai’s slide brochure ערבול (Hashing) חומר קריאה לשיעור זה: Chapter 12- Hash tables (pages 219—243) Geiger & Itai, 2001

2 Lecture7 of Geiger & Itai’s slide brochure
ערבול (Hashing) ראינו שלושה מימושים שונים למילון: AVL, עצי 2-3 ורשימת דילוגים הפעולות הבסיסיות (חיפוש, הכנסה, והוצאה) מתבצעות כל אחת ב-O(log n) האם אפשר לממש פעולות אלו בסיבוכיות זמן יותר טובה? 1 Data 2 2 Data k k m-1 תשובה: כן! באמצעות מערך אפשר לממש כל פעולה ב-O(1) Geiger & Itai, 2001

3 ערבול (Hashing) מדוע לפיכך נרצה להשתמש בעצי חיפוש מאוזנים או ברשימות דילוגים? תשובה: לעיתים גודל התחום של ערכי המפתחות גדול בהרבה ממספר המפתחות בהם משתמשים. דוגמא 1: מספרי תעודת זהות מורכבים מתשע ספרות עשרוניות כלומר קיימים 109 מפתחות אך בישראל יש פחות מ 107 אנשים. לפיכך שימוש במערך ינצל פחות מ 1% בודד של הזיכרון המוקצה למערך. דוגמא 2: מספר המחרוזות של אותיות עבריות באורך 30 (באמצעותן ניתן לתאר שם פרטי, שם אמצעי, ושם משפחה של תושבי ישראל) הוא 2230 בעוד מספר האנשים קטן מ 107. אבחנה: אם נשתמש במערך, זמן של כל פעולה יהיה אמנם O(1), אך דרישות המקום הן O(m) , כאשר m הוא גודל הטווח. ייתכן n = o(m). cs,Technion

4 ערבול (Hashing) מימוש מילון באמצעות מערך נקרא גישה ישירה (Direct Addressing ): המפתח עצמו משמש כאינדקס במערך. כאשר מרחב המפתחות גדול נחשב את האינדקס מתוך המפתח באמצעות פונקצית ערבול. המטרה לממש את פעולות החיפוש,הכנסה, והוצאה בזמן ממוצע של O(1). נגדיר פונקצית ערבול (hash):h: U  {0,…,m-1} אשר בהינתן מפתח בתחום U מחשבת אינדקס בטווח המתאים. האינדקס של מפתח k הוא h(k). דוגמא:m = 10 h(k) = k mod 10 51, 17, 15, 92, 88, 29 51 1 92 2 3 4 15 5 6 17 7 88 8 29 9 בשיטת הערבול נוצרות התנגשויות כאשר x  y אבל h(x) = h(y). לדוגמא:h(81) = 1 = h(51) . cs,Technion

5 פתרון להתנגשויות באמצעות "שרשראות" (chaining)
הפעולות: x1 x3 x4 x2 x5 X1 X4 X5 X3 X2 T Insert(T,x) הכנס את x בראש הרשימה T[ h(x.key)]. זמן במקרה הגרוע ביותר O(1). Search(T,k) חפש איבר עם מפתח k ברשימה T[ h(k)] זמן במקרה הגרוע ביותר (אורך הרשימה). Delete(T,x) סלק את x מהרשימה T[ h(x.key)]. זמן במקרה הגרוע ביותר (אורך הרשימה) . cs,Technion

6 דוגמא נניח: m = 10 h(k) = k mod m 53, 62, 17, 19, 37, 12, 57 קלט: 12
4 5 6 7 8 9 12 62 12 53 57 17 37 57 37 57 19 הערה: 10 = m נבחר לצורכי נוחיות ההסבר. נראה בהמשך שבחירה טובה יותר היא 11. cs,Technion

7 ניתוח זמנים במקרה הגרוע ביותר כל האיברים נכנסו לאותה הרשימה ואז זמן חיפוש/הוצאה הוא (n) . ברור לפיכך שאין משתמשים בערבול בגלל הזמן המקסימלי לפעולה אלא בגלל הזמן הממוצע לפעולה. נרצה לבחור פונקצית ערבול שמפזרת היטב את המפתחות לרשימות השונות. נניח לרגע שהצלחנו, כלומר h מפזרת את המפתחות באופן אחיד. הנחה זו נקראת הנחת הפיזור האחיד הפשוט (simple uniform hash). ננתח כעת את זמני החיפוש תחת הנחת הפיזור האחיד הפשוט. הגדרה: יהי n מספר המפתחות בשימוש ויהי m גודל הטבלה פקטור העומס מוגדר ע"י = n / m . תחת הנחת הפיזור האחיד הפשוט ממוצע אורך שרשרת הוא , מכיוון שהאיברים מתחלקים שווה בשווה בין השרשראות השונות. cs,Technion

8 ניתוח זמנים (המשך) משפט (חיפוש כושל): בשיטת השרשראות ותחת הנחת הפיזור האחיד הפשוט הזמן הממוצע לחיפוש כושל הוא (1+). הוכחה: בהנחת הפיזור האחיד הפשוט כל מפתח מגיע באקראי לאחת מ-m הרשימות. הזמן לחיפוש כושל הוא לפיכך הזמן הממוצע לחפש באחת הרשימות עד סופה. אורכה הממוצע של רשימה בהנחת הפיזור האחיד הוא  = n / m . לפיכך בממוצע יידרש זמן ) (1+ (הכולל את זמן בדיקת המצביע בסוף הרשימה). 1 2 3 4 5 6 7 8 9 62 12 53 17 37 57 19 ארבעה מצביעים cs,Technion

9 ניתוח זמנים (המשך) משפט (חיפוש מוצלח): בשיטת השרשראות ותחת הנחת הפיזור האחיד הפשוט הזמן הממוצע לחיפוש מוצלח הוא (1+/2). הוכחה: נאמר שבזמן החיפוש ישנם n מפתחות שהוכנסו בסדר k1,…,kn . מהו זמן חיפוש הממוצע של המפתח ki ? אחרי מפתח זה נוספו n-i מפתחות נוספים. לכן בממוצע גודל הרשימה משמאל למפתח ki הוא (n-i)/m. 1 2 3 4 5 6 7 8 9 62 12 53 17 37 57 19 המפתח ki אחרי ki לפני ki מכאן שזמן החיפוש הממוצע של המפתח ki הוא (n-i)/m 1+ זמן החיפוש הממוצע t למפתח כלשהו יהיה לפיכך:

10 ניתוח זמנים (המשך) לפיכך, כאשר סדר הגודל של מספר המפתחות n בהם משתמשים הוא כגודל המערך m, כלומר עבור n = O(m), נקבל שגורם העומס קבוע כלומר  = O(1) ולכן כל הפעולות דורשות זמן ממוצע O(1). לדוגמא עבור 2100 מפתחות מטווח כלשהו U של מספרים שלמים, נאמר עד 106, נוכל להחזיק מערך ובו 700 מקומות ובממוצע אורך כל שרשרת יהיה 3 וזמני החיפוש יהיו בהתאם. cs,Technion

11 פתרון ללא שרשראות להתנגשויות
לא נשתמש בשרשראות, אלא כל האיברים יוכנסו לטבלה. שיטה כזו נקראת Open addressing . נבחן שלושה פתרונות להתנגשויות : סריקה ליניארית, ערבול נשנה, וערבול כפול. סריקה ליניארית linear probing -- אם המקום המיועד h(k) תפוס, שים במקום הבא מודולו m. 12 57 1 2 3 4 5 6 7 8 9 53, 62, 17, 19, 37, 12, 57 דוגמא: m = h(k) = k mod m קלט: 12 62 53 57 37 17 19 12 62 57 37 17 19 12 57 37 12 57 37 17 19 12 57 37 19 ברור שבשיטות open addressing פקטור העומס ≥ (n  m) .

12 הוצאה בשיטת linear probing
כיצד נוציא איברים ? לא ניתן פשוט למחוק איבר שכן שרשרת החיפוש תינתק. דוגמא: m = h(k) = k mod m 53, 62, 17, 19, 37, 12 ,57 קלט: 1 2 3 4 5 6 7 8 9 12 62 53 57 17 19 12 62 53 57 37 17 19 הוצא 37 חפש 17?

13 הוצאה בשיטת linear probing
פתרון: בזמן ההוצאה הוצא את כל האיברים עד לרווח הבא, והכנס את כולם חזרה פרט לאיבר שרוצים להוציא. 12 62 53 57 19 17 12 62 53 57 37 17 19 1 2 3 4 5 6 7 8 9 12 62 53 57 37 17 19 הוצא 37 חפש 17! cs,Technion

14 הוצאה בשיטת המציבה כדי לא לנתק את שרשרת החיפוש תינתק נסמן את מקום האיבר שהוצא בסימן deleted . (שיטת המציבה) בזמן חיפוש x, במידה וניתקל בסימן delete, נמשיך את סריקת הרשימה עד למציאת x או עד שנגיע למקום ריק (המסומן ב- Null). בזמן הכנסת x, במידה וניתקל בסימן delete, נשתמש במקום זה לשמירת x, אחרת נשמור את x במקום הריק בסוף הרשימה (המסומן ב-Null ). 1 2 3 4 5 6 7 8 9 53, 62, 17, 19, 37, 12, 57 דוגמא: m = h(k) = k mod m קלט: 12 62 53 57 37 17 19 12 62 53 57 27 17 19 12 62 53 57 delete 17 19 הכנס 27 חפש 17, הוצא 37,

15 יתרונות וחסרונות היתרון העיקרי של שיטת המציבה הוא פשטות. אבל …
כאשר השימוש דורש הוצאות, אורך החיפוש תלוי גם באיברים שכבר הוצאו ולא רק באיברים שכרגע במבנה. דוגמאות לשימוש במילון ללא הוצאות: טבלה של שמות משתנים בהרצת תוכנית (Symbol Table). מספרי תעודות זהות אינם ממוחזרים. נתאר כעת שיטות נוספות ל-open addressing. שיטות אלו שימושיות במיוחד במימושי מילון ללא הוצאות. כאשר יש צורך בהוצאות, עדיפה שיטת הרשימות המקושרות. cs,Technion

16 ערבול נשנה Rehashing --
נניח שברשותנו סדרה אינסופית של פונקציות ערבול: h0,h1,h2,… ננסה לשמור את x במקום h0(x). אם תפוס, ננסה במקום h1(x). נמשיך עד שנצליח. סריקה ליניארית (linear probing) היא מקרה פרטי בו: hi(x) = h(x) + i . cs,Technion

17 ערבול כפול Double Hashing --
נגיע לתוצאות דומות לערבול נשנה ע"י שתי פונקציות בלבד d, h. כאשר: hi(x) = h(x) + i d(x) הפונקציות d, h נבחרות באופן בלתי תלוי. מהו היחס הרצוי בין d(x) לגודל הטבלה m ? גודל הטבלה ו- d(x) צריכים להיות מספרים זרים כך ש ,hm-1(x) …h0(x), תכסה את כל האינדקסים האפשריים בתחום {0,…,m-1}. לפיכך נוח לבחור את m להיות מספר ראשוני. הוצאות נעשות ע"י שימוש בסימון delete . cs,Technion

18 ניתוח זמנים עבור Rehashing
הנחת הפיזור האחיד: הסדרה (h0(x),h1(x),h2(x),…hm-1(x)) היא פרמוטציה אקראית של (0,…,m-1). משפט: בהנחת הפיזור האחיד, בשיטת ערבול rehashing מתקיים: זמן ממוצע של חיפוש כושל קטן מ- 1/(1 - ) זמן ממוצע של חיפוש מוצלח קטן מ- חיפוש מוצלח חיפוש כושל 3.386 2 0.5 3. 261 5 0.8 3.669 10 0.9 הוכחה בספר הלימוד: Introduction to algorithms, Cormen et al., pp cs,Technion

19 ניתוח זמנים עבור סריקה ליניארית
משפט: בהנחת הפיזור האחיד הפשוט, בשיטת ערבול open addressing בסריקה ליניארית מתקיים: זמן ממוצע של חיפוש כושל קטן מ- זמן ממוצע של חיפוש מוצלח קטן מ- סריקה ליניארית חיפוש מוצלח סריקה ליניארית חיפוש כושל ערבול נשנה חיפוש מוצלח ערבול נשנה חיפוש כושל 1.5 2.5 1.836 2 0.5 3.0 13.0 3.261 5 0.8 5.5 50.5 3.669 10 0.9 הוכחה בספר : Knuth, The art of computer programming, Vol 3, 1973 מסקנה: המשפט מראה שאפשר להשתמש בסריקה ליניארית, כל עוד הטבלה לא מלאה מדי (80%). cs,Technion

20 פונקציות ערבול דרישות מפונקציות ערבול: מפזרת היטב וקלה לחישוב.
שיטת החילוק מודולו m: h(x) = x mod m רצוי ש-m: לא יהיה חזקה של 2 או 10. בחזקות של 2 פונקצית הערבול מסתמכת רק על log2(m) הביטים הראשונים (LSB). בחזקות של עשר, פונקצית הערבול מסתמכת רק על log10(m) הספרות הראשונות. רצוי שפונקציות הערבול ישתמשו בכל האינפורמציה הנמצאת במפתח כדי לקרב עד כמה שניתן את הנחת הפיזור האחיד. יהיה ראשוני שאינו קרוב לחזקה של 2. חזקות קרובות של 2 גורמות לפיזור לא אחיד כאשר המפתחות כתובים בבסיס שהוא חזקה של 2, למשל מחרוזות תווים נכתבות בבסיס 28 = 256 . הערה:רצוי לבדוק את פונקצית הערבול על תת קבוצה של מפתחות "אמיתיים" וכך לוודא שהנחת הפיזור האחיד מתקיימת בקרוב. cs,Technion

21 פונקציות ערבול (המשך) שיטת הכפל בקבוע 1 > a > 0
פונקציות ערבול (המשך) שיטת הכפל בקבוע 1 > a > 0 הכפל את המפתח k בקבוע a. מצא את החלק השבור של התוצאה. הכפל את החלק השבור ב- m ועגל כלפי מטה: h(k) = m  (ak mod 1) הערך של m אינו קריטי. ערך של a הגורם לפיזור טוב הוא : דוגמא:m = k = h(k) = 10000  (  mod 1) = 10000  ( mod 1) = 10000   =  …  = 41 cs,Technion

22 פונקציות ערבול למחרוזות ארוכות
נשתמש בקוד ”a” = 97 = :ascii ”b” = 98 = וכך הלאה … פתרון נאיבי: בצע xor ביט ביט. לדוגמא: h(“ab”) = h( ( ) xor ( )) = ( ) = 3 בהינתו מחרוזת s0,…, sk בצע: =ascii(s0) xor … xor ascii(sk) (h(s0,…, sk חסרון ראשון: h(“aa”) = h( ( ) xor ( )) = ( ) = 0 h{“bb”) = h( ( ) xor ( )) = ( ) = 0 התוצאה אפס מתקבלת כאשר כל אות מופיעה מספר זוגי של פעמים:h{“abccba”) = 0 חסרון שני: טווח הערכים מוגבל.h(x)  255 cs,Technion

23 פונקציות ערבול למחרוזות ארוכות (המשך)
פתרון עדיף: (על עקרון השפעת הפרפר מגינאה על מזג האוויר – שינוי קטן מביא שינוי גדול) בחר פרמוטציה אקראית (0,…, 255) של 0…255 ואחסן אותה במערךT . בצע xor בין האות הראשונה s0 של המפתח והערך T[0]. התוצאה a1 נמצאת בתחום0…255 . בשלב ה-i בצע xor בין האות si של המפתח והערך T[ai]כאשר ai היא תוצאת ה-xor בשלב הקודם. תוצאת פונקצית הערבול היא תוצאת ה-xor עם האות האחרונה של המפתח כלומר hash(key) = sn xor T[an] דוגמא: hash(aa) 38 23 118 T hash(a) = T[0] xor 97 = xor = = 118 hash(aa) = T[ hash(a) ] xor a = T[118] xor 97 = xor = 71 הערה: בשיטה זו נפתרה בעיית האותיות המופיעות מספר זוגי של פעמים. cs,Technion

24 פונקציות ערבול למחרוזות ארוכות (המשך)
מימוש של פונקצית הערבול: int hash(char *s) { int h = 0; char *p; for (p=s; *p; p++) h = T[h]^ *p; /* Xor */ return h; } cs,Technion

25 פונקציות ערבול למחרוזות ארוכות (המשך)
כדי להתגבר על בעיית הטווח ניתן להשתמש בשתי פרמוטציות T1, T2 ולשרשר את התוצאות. hash(k) = [hash1(k), hash2(k)] = hash1(k) * hash2(k) גודל הטווח החדש, כלומר גודל טבלת הערבול, הוא=65, = 216. (בעוד גודל כל Ti הוא 256). ניתן להגיע לטווח הרצוי ע"י שימוש במספר קטן של פרמוטציות נוספות. תוצאה דומה מתקבלת אם במקום hash2 נוסיף 1 לאות הראשונה של המחרוזת ונשתמש שוב בפונקצית הערבול hash1. לדוגמא: hash(acb) = hash1(acb) * hash1(bcb) cs,Technion

26 ערבול אוניברסלי לכל בחירה של פונקצית ערבול קיימת סדרה גרועה של מפתחות כך שתווצר רשימה באורך מקסימלי. תכונה זו יכולה ליצור בעיה. לדוגמא, יתכן מתכנת המשתמש באופן עקבי בשמות מסוימים למשתני התוכניות שהוא כותב ולצערו פונקצית הערבול הבונה את ה-symbol table ממפה את כל השמות הנ"ל לאותו המקום בטבלת הערבול. לפיכך כל תוכנית מחשב של משתמש זה אינה יעילה כפי שיכולה הייתה להיות ! הפתרון: לבחור באקראי, בזמן יצירת טבלת ערבול, פונקצית ערבול מתוך קבוצת פונקציות שהוגדרה מראש. נרצה שקבוצת הפונקציות תהיה כזו, שעבור כל סדרת מפתחות, בחירה אקראית של אחת הפונקציות תיצור פיזור טוב. הגדרה: תהי H קבוצת פונקציות ערבול מתחום U לקבוצה .{0,…,m-1} הקבוצה H נקראת אוניברסלית אם לכל זוג מפתחות שונים x,y  U מספר הפונקציות עבורן h(x) = h(y) הוא |H|/m . נראה כעת ששימוש בקבוצה אוניברסלית גורם לפיזור טוב. אח"כ נראה כיצד לבנות קבוצה כזו. אבחנה: לכל זוג מפתחות x ו-y,ההסתברות p שבבחירה אקראית של פונקצית ערבול מתוך H, תהיה התנגשות בין x ו-y היא p = (|H|/m)/|H| = 1/m .

27 ערבול אוניברסלי (המשך)
משפט: תהי H קבוצה אוניברסלית של פונקציות ערבול לתוך טבלהT בגודל m. אם h נבחרה באקראי מתוך H, ונשתמש בה לערבול n מפתחות כלשהם, אזי לכל מפתח, המספר הצפוי של התנגשויות בשיטת הרשימות המקושרות שווה ל-(n-1)/m = α-1/m . הוכחה: ראינו שההסתברות להתנגשות של מפתח מסוים x עם מפתח מסוים y היא p = 1/m. המספר הצפוי של התנגשויות של מפתח מסוים x עם מפתח כלשהו נתון לפיכך ע"י: מסקנה: מספר ההתנגשויות הצפוי לכל מפתח קטן מגורם העומס. cs,Technion

28 בניית קבוצה אוניברסלית
נבחר את גודל הטבלה להיות מספר ראשוני m. נשבור כל מפתח x ל- r + 1 חלקים באורך קבוע x = [ x0,…,xr]. (למשל באורך בייט = 8 ביטים). מספר הביטים יבחר כך שהערך של xi יהיה לכל היותר m. לכל סדרה a = [a0,…,ar] מהתחום {0,..,m-1} r+1 נגדיר פונקצית ערבול ha(x) בצורה הבאה: קבוצת הפונקציות H מוגדרת להיות a {ha} ומספר הפונקציות בקבוצה זו הוא: mr+1. דרך השימוש בשיטה זו: נקצה טבלת ערבול T בגודל m, נגריל מספר a ונשתמש בפונקצית הערבול ha לכל הפעולות דוגמא: m=257, טווח המפתחות נשבור כל מפתח לשלושה חלקים באורך 8 ביטים. נניח שהוגרלו המספרים a=[248,223, 101]. בהינתן המפתח x = 1025 = = 4·28 +1·20 = [0,4,1] נחשב (248  1) mod 257 = 993 mod 257 = 222 cs,Technion

29 בניית קבוצה אוניברסלית (המשך)
משפט: קבוצת הפונקציות H = {ha} שהוגדרה בשקף הקודם היא קבוצה אוניברסלית. הוכחה: יהיו x = [x0,…,xr] ו- y = [y0,…,yr] מפתחות שונים. ללא הגבלת הכלליות נניח x0y0. אנו טוענים שלכל בחירה של a1,…,ar קיים ערך יחיד ל-a0 כך שמתקיים ha(x)=ha(y). הערך a מתקבל מהפתרון היחיד למשוואה: הניתנת לשכתוב כדלקמן: בהנחה שהטענה נכונה, נובע שכל זוג מפתחות x,y מתנגשים עבור mr ערכים של a שכן לכל ערך של (a1,…,ar) קיים ערך אחד a0 עבורו x,y מתנגשים. נזכור שמספר הפונקציות ב-H הוא mr+1. לפיכך, ההסתברות ש-x ו-y יתנגשו היא mr/mr+1 = 1/m כנדרש מקבוצה אוניברסלית. cs,Technion

30 בניית קבוצה אוניברסלית (המשך)
טענה: למשוואה הבאה יש פתרון והפתרון יחיד. נזכר שכאשר m ראשוני מתקיים: עבור כל מספר z (שאינו 0) קיים מספר w יחיד כך ש z  w = 1 (mod m) במילים אחרות: לכל מספר הופכי (כפלי) יחיד! למשל 2  2 = 1 (mod 3)  1 = 1 (mod 3) במשוואה הנתונה z = x0 – y0  0 נכפיל את המשוואה בהופכי של z ונקבל את הפתרון היחיד ל-a0. cs,Technion

31 מגבלות לערבול צריך לדעת מראש סדר גודל למספר האיברים שמתעתדים להכניס למבנה (n). פתרון חלקי: כאשר טבלת ערבול מתמלאת ניתן להקצות טבלה חדשה בגודל כפול, להכניס את כל האיברים לטבלה החדשה, ולהיפטר מהטבלה הישנה. 4n 2n n הזמן המשוערך הממוצע יהיהO(1) למרות שמדי פעם תתבצע פעולה יקרה. cs,Technion

32 שימוש: בעיית היחידותElement Uniqueness
נתונים מספרים0 x0,…,xn-1 < T מצא אם קיים ij עבורו xi = xj. פתרון ראשון – מיון: זמן O(n log n) פתרון שני – ערבול: הכנס את המספרים לטבלת ערבול בגודל O(n) (שיתכן וקטנה בהרבה מ-T ). בזמן התנגשות, בדוק שוויון. זמן ממוצע O(n). cs,Technion


Download ppt "ערבול (Hashing) חומר קריאה לשיעור זה:"

Similar presentations


Ads by Google