שאלת מבחן במבני נתונים - אוניברסיטת בר-אילן 2017 - Union-Find
(20 נקודות) אנו מתחזקים גרף (לא מכוון) על קבוצה של קודקודים, תחת הוספת קשתות(אך קשתות לעולם אינן נמחקות לאחר הוספה). הצע מבנה נתונים התומך בפעולות הבאות:
א. – הוספת קשת מקודקוד לקודקוד .
ב. – האם קיים מסלול כלשהו בין ל- החזר true, אחרת החזר false.
ניקוד מלא ינתן לתשובה בה הוספת קשת לוקחת , שאילתת לוקחת זמן, וגודל מבנה הנתונים הינו .
א. – הוספת קשת מקודקוד לקודקוד .
ב. – האם קיים מסלול כלשהו בין ל- החזר true, אחרת החזר false.
ניקוד מלא ינתן לתשובה בה הוספת קשת לוקחת , שאילתת לוקחת זמן, וגודל מבנה הנתונים הינו .
העתק שאלה
שתף שאלה
סמן כחשוב
סמן כבוצע
אוניברסיטת בר-אילןמועד א2017סמסטר ב
★★★★★
Union-Findגרפיםסיבוכיות זמןסיבוכיות מקוםניתוח מופחת
ניתן לפתור את הבעיה על ידי תחזוק מבנה נתונים העוקב אחר רכיבי הקשירות בגרף. כל הוספת קשת יכולה לכל היותר לאחד שני רכיבי קשירות.
הבעיה של מעקב אחר קשירות בגרף תחת הוספת קשתות ניתנת לפתרון יעיל באמצעות מבנה נתונים מסוג Union-Find (איחוד-מציאה), המכונה גם מבנה נתונים לקבוצות זרות (Disjoint Set Union).
הרעיון המרכזי הוא לתחזק אוסף של קבוצות זרות, כאשר כל קבוצה מייצגת רכיב קשירות בגרף. בתחילה, הגרף מכיל קודקודים ללא קשתות, ולכן כל קודקוד מהווה רכיב קשירות נפרד. מבנה הנתונים יתחיל עם קבוצות, כאשר כל קבוצה מכילה קודקוד אחד בלבד.
מימוש מבנה הנתונים:
נשתמש במערך
כדי לעמוד בדרישות הסיבוכיות, נשתמש בשתי אופטימיזציות:
1. איחוד לפי גודל (Union by Size): נתחזק מערך נוסף,
2. כיווץ מסלולים (Path Compression): במהלך ביצוע פעולת
מיפוי הפעולות הנדרשות:
א. `Insert(u,v)`: פעולה זו ממופה לפעולת
ב. `Connect?(u,v)`: פעולה זו בודקת האם קיים מסלול בין ל-. זה שקול לבדיקה האם ו- שייכים לאותו רכיב קשירות. במבנה שלנו, זה מתורגם לבדיקה האם
ניתוח סיבוכיות:
* סיבוכיות מקום: אנו משתמשים בשני מערכים (
* סיבוכיות זמן: כאשר משתמשים בשתי האופטימיזציות, איחוד לפי גודל וכיווץ מסלולים, הסיבוכיות המופחתת (amortized) של כל פעולת
* פעולת
* פעולת
שתי הפעולות עומדות בדרישת הסיבוכיות של .
הרעיון המרכזי הוא לתחזק אוסף של קבוצות זרות, כאשר כל קבוצה מייצגת רכיב קשירות בגרף. בתחילה, הגרף מכיל קודקודים ללא קשתות, ולכן כל קודקוד מהווה רכיב קשירות נפרד. מבנה הנתונים יתחיל עם קבוצות, כאשר כל קבוצה מכילה קודקוד אחד בלבד.
מימוש מבנה הנתונים:
נשתמש במערך
parent בגודל , כך ש-parent[i] מחזיק את "ההורה" של קודקוד במבנה העצים שמייצג את הקבוצות. כל רכיב קשירות מיוצג כעץ, ושורש העץ (קודקוד המקיים parent[r] == r) הוא הנציג של רכיב הקשירות כולו.כדי לעמוד בדרישות הסיבוכיות, נשתמש בשתי אופטימיזציות:
1. איחוד לפי גודל (Union by Size): נתחזק מערך נוסף,
size, בגודל . עבור כל שורש , size[r] יכיל את מספר הקודקודים בעץ ש-r הוא שורשו. כאשר מאחדים שני עצים עם שורשים ו-, נחבר את שורש העץ הקטן יותר להיות בן של שורש העץ הגדול יותר. זה מבטיח שגובה העצים יישאר נמוך, בסדר גודל של .2. כיווץ מסלולים (Path Compression): במהלך ביצוע פעולת
Find(u) (המוצאת את נציג הקבוצה של ), לאחר מציאת השורש , נגרום לכל הקודקודים שהיו במסלול מ- ל- להצביע ישירות על . אופטימיזציה זו "משטיחה" את העצים באופן דרמטי ומאיצה מאוד פעולות עתידיות.מיפוי הפעולות הנדרשות:
א. `Insert(u,v)`: פעולה זו ממופה לפעולת
Union(u,v) במבנה הנתונים. ראשית, נמצא את הנציגים של ו- על ידי קריאה ל-Find(u) ו-Find(v). אם הנציגים זהים, הקודקודים כבר נמצאים באותו רכיב קשירות והוספת הקשת לא משנה את הקשירות, ולכן אין צורך לעשות דבר. אם הנציגים שונים, נאחד את שתי הקבוצות (העצים) שלהם באמצעות איחוד לפי גודל.ב. `Connect?(u,v)`: פעולה זו בודקת האם קיים מסלול בין ל-. זה שקול לבדיקה האם ו- שייכים לאותו רכיב קשירות. במבנה שלנו, זה מתורגם לבדיקה האם
Find(u) == Find(v). אם הנציגים זהים, הפונקציה תחזיר true, אחרת false.ניתוח סיבוכיות:
* סיבוכיות מקום: אנו משתמשים בשני מערכים (
parent, size) בגודל . לכן, סיבוכיות המקום היא , כנדרש.* סיבוכיות זמן: כאשר משתמשים בשתי האופטימיזציות, איחוד לפי גודל וכיווץ מסלולים, הסיבוכיות המופחתת (amortized) של כל פעולת
Find או Union היא , כאשר היא הפונקציה ההופכית לפונקציית אקרמן. פונקציה זו גדלה לאט באופן קיצוני, ולכל מעשי ערכה קטן מ-5. סיבוכיות זו טובה משמעותית מהסיבוכיות הנדרשת של .* פעולת
Insert(u,v) מבצעת שתי קריאות Find ופעולת איחוד אחת במקרה הגרוע, ולכן זמן הריצה המופחת שלה הוא .* פעולת
Connect?(u,v) מבצעת שתי קריאות Find, ולכן זמן הריצה המופחת שלה הוא .שתי הפעולות עומדות בדרישת הסיבוכיות של .