Transcript Quicksort

10 ‫תרגול‬
Huffman code
QuickSort
‫‪Huffman code‬‬
‫• קוד הופמן – אלגוריתם קידוד לכיווץ נתונים שמשתמש‬
‫בתור עדיפות לקביעת הקידוד‪.‬‬
‫• תכונות האלגוריתם – בהינתן מידע המורכב מקבוצת‬
‫סמלים ‪( C‬לדוגמה ‪ C‬יכולה להיות קבוצת האותיות בשפה‬
‫כלשהי ‪ +‬סימני פיסוק) האלגוריתם משתמש בתור‬
‫עדיפות כדי לקבוע אילוי קידודים לתת לסמלים השונים‬
‫בקבוצה‪.‬‬
‫– האלגוריתם בונה עץ בינארי (עץ הופמן) שבו הסמלים‬
‫משויכים לעלים‪ ,‬ואורך הקידוד של סמל הוא עומק העלה אליו‬
‫הוא משויך‪.‬‬
‫– כדי למצוא את הקידוד של סמל כלשהו‪ ,‬נתחיל בשורש ונלך‬
‫במסלול עד לעלה אליו הוא משויך‪ .‬נוסיף ‪ 0‬כל פעם שעברנו‬
‫לבן השמאלי ו‪ 1‬כל פעם שעברנו לבן הימני‬
‫– הקידוד שנוצר הוא אופטימלי (מבין הקידודים המקודדים כל‬
‫סמל בנפרד)‬
‫קוד לבניית העץ‬-‫פסאודו‬
• Huffman (C)
n ← |C|
Q ← { new priority queue for the letters in C }
for i ← 1 to n-1
z ← allocate new node
x ← Extract_Min(Q)
y ← Extract_Min(Q)
z.left ← x
z.right ← y
frequency (z) ← frequency (x) + frequency (y)
Insert(Q, z)
‫דוגמה‬
• Example Huffman tree with 4 symbols (C={e,s,x,y})
• Frequencies:
x=1
y=1
s=7
e=20
• Encoding:
e: 1
s: 01
x: 000
y: 001
‫שאלה ‪1‬‬
‫‪ .a‬מהו קוד הופמן האופטימלי עבור רצף התדירויות‬
‫הבא‪ ,‬המבוסס על ‪ 8‬מספרי פיבונאצ'י הראשונים‬
‫‪a:1 b:1 c:2 d:3 e:5 f:8 g:13 h:21‬‬
‫‪ .b‬הכלילו את תשובתכם לכדי מציאת קוד הופמן‬
‫האופטימלי כאשר התדירויות הנתונות הן עבור ‪n‬‬
‫מספרי פיבונאצ'י הראשונים‬
‫שאלה ‪1‬‬
‫‪ .a‬מהו קוד הופמן האופטימלי עבור רצף התדירויות‬
‫הבא‪ ,‬המבוסס על ‪ 8‬מספרי פיבונאצ'י הראשונים‬
‫‪a:1 b:1 c:2 d:3 e:5 f:8 g:13 h:21‬‬
‫תשובה‪:‬‬
‫מאחר וישנן ‪ 8‬תדירויות (‪ 8‬אותיות ב‪-‬א"ב)‪ ,‬גודל התור‬
‫ההתחלתי יהיה ‪ ,n=8‬ויידרשו ‪ 7‬מיזוגים לשם בניית‬
‫העץ‪.‬‬
‫העץ הסופי ייצג את הקידוד האופטימלי‪.‬‬
‫מילת‪-‬הקוד עבור כל אות היא רצף התוויות שעל הצלעות‬
‫(צלע לבן שמאלי – ‪ ,0‬צלע לבן ימני – ‪ )1‬במסלול‬
‫שמוביל מהשורש לעלה שמייצג את האות‪.‬‬
‫שאלה ‪1‬‬
‫‪ .a‬מהו קוד הופמן האופטימלי עבור רצף התדירויות‬
‫הבא‪ ,‬המבוסס על ‪ 8‬מספרי פיבונאצ'י הראשונים‬
‫‪a:1 b:1 c:2 d:3 e:5 f:8 g:13 h:21‬‬
‫תשובה‪:‬‬
‫‪0‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪h:‬‬
‫‪g:‬‬
‫‪f :‬‬
‫‪e:‬‬
‫‪d:‬‬
‫‪c:‬‬
‫‪b:‬‬
‫‪a:‬‬
‫שאלה ‪1‬‬
‫‪ .b‬הכלילו את תשובתכם לכדי מציאת קוד הופמן‬
‫האופטימלי כאשר התדירויות הנתונות הן עבור ‪ n‬מספרי‬
‫פיבונאצ'י הראשונים‬
‫תשובה‪:‬‬
‫ניתן לראות שבסעיף הקודם העץ שהתקבל הוא למעשה‬
‫ענף אחד ארוך שעליו תלויים הרבה עלים‪.‬‬
‫זה נכון למספרי פיבונאצ'י באופן כללי‪ ,‬שכן מתכונת‬
‫הרקורסיה של פיבונאצ'י נובע ש‪:‬‬
‫𝑛‬
‫= ‪𝐹𝑛+2‬‬
‫‪𝐹𝑖 + 1‬‬
‫‪𝑖=0‬‬
‫שאלה ‪1‬‬
‫‪ .b‬הכלילו את תשובתכם לכדי מציאת קוד הופמן האופטימלי כאשר‬
‫התדירויות הנתונות הן עבור ‪ n‬מספרי פיבונאצ'י הראשונים‬
‫תשובה‪:‬‬
‫𝑘‬
‫ניתן להוכיח זאת באמצעות אינדוקציה‪:‬‬
‫= ‪𝐹𝑘+2‬‬
‫‪𝐹𝑖 + 1‬‬
‫‪𝑖=0‬‬
‫המספרים ‪ 1,1,2,3‬מהווים את הבסיס‬
‫נניח את נכונות הטענה לכל מספרי פיבונאצ'י שקטנים מ‪𝐹𝑛+2 -‬‬
‫צעד‪ :‬הוכחת נכונות עבור ‪𝐹𝑛+2‬‬
‫𝑛‬
‫‪𝐹𝑖 + 1‬‬
‫‪𝑛−1‬‬
‫= 𝑛𝐹 ‪𝐹𝑖 + 1 +‬‬
‫‪𝑖=0‬‬
‫𝑖𝐹 ‪,𝐹𝑛+2 > 𝑛𝑖=0‬‬
‫= 𝑛𝐹 ‪𝐹𝑛+2 = 𝐹𝑛+1 +‬‬
‫‪𝑖=0‬‬
‫וברור שמתקיים ‪ 𝐹𝑛+2 > 𝐹𝑛+1‬לכן ‪𝐹𝑛+2‬‬
‫לכן מתקיים‬
‫נבחר אחרי כל מספרי פיבונאצ'י שקטנים ממנו כבר אוחדו לעץ אחד‪.‬‬
‫שאלה ‪2‬‬
‫‪ .a‬בהינתן סדרת התדירויות הבאה עבור קוד הופמן‪𝑓𝑖 :‬‬
‫‪4‬‬
‫‪𝑖=1‬‬
‫𝑖 =‬
‫𝑛‪2 𝑖 ∈ 2..‬‬
‫ציירו את המבנה של עץ הופמן שמתאר את הסדרה‪.‬‬
‫פתרון‪:‬‬
‫הסבר‪:‬‬
‫• באופן דומה לסדרת פיבונאצ'י‪ ,‬ניתן לראות שמתקיים 𝑗𝑓‬
‫‪= 𝑓1 + 𝑓2 + ⋯ + 𝑓𝑗−1‬‬
‫• לכן‪ ,‬בכל שלב בבניית העץ נבחר את השורש של תת‪-‬העץ‬
‫‪ 𝑓1 −− −𝑓𝑖−1‬שכבר נוצר‪ ,‬ונקבל את העץ בדיאגרמה‪.‬‬
‫שאלה ‪2‬‬
‫‪ .b‬מצאו רשימת תדירויות כך שעץ הופמן עבור‬
‫רשימה זו יבנה בצורה דטרמיניסטית את המבנה‬
‫הבא‪:‬‬
‫‪22‬‬
‫‪10‬‬
‫‪12‬‬
‫‪7‬‬
‫‪4‬‬
‫‪5‬‬
‫‪3‬‬
‫תשובה (דוגמה)‪:‬‬
‫‪2,2,3,5,5,5‬‬
‫‪2‬‬
‫‪2‬‬
‫‪5‬‬
‫‪5‬‬
‫שאלה ‪2‬‬
‫‪.c‬‬
‫מצאו נוסחת תדירויות כך שקוד הופמן עבור תדירויות אלו יבנה‬
‫בצורה דטרמיניסטית את המבנה הבא‪:‬‬
‫תשובה‪:‬‬
‫בכדי ליצור את המבנה הזה‪ ,‬נרצה ששני האלמנטים הבאים בסדרה‬
‫ייבחרו לפני האיחוד עם תת העץ שכבר קיים‪.‬‬
‫התבנית של הסדרה מבוססת על העקרון שבכל רמה‪ ,‬התדירות של שני‬
‫האלמנטים הבאים קטנה מסכום התדירויות עד לאותו רגע‪.‬‬
‫שאלה ‪2‬‬
‫‪.c‬‬
‫מצאו נוסחת תדירויות כך שקוד הופמן עבור תדירויות אלו יבנה‬
‫בצורה דטרמיניסטית את המבנה הבא‪:‬‬
‫לדוגמה‪:‬‬
‫‪𝑠𝑜𝑚𝑒 𝑐𝑜𝑛𝑠𝑡𝑎𝑛𝑡 𝑐 ≥ 1‬‬
‫‪𝑖≤4‬‬
‫‪𝑓𝑖−1‬‬
‫𝑛𝑒𝑣𝑒 𝑠𝑖 𝑖‬
‫= 𝑖𝑓‬
‫𝑒𝑠𝑙𝑒‬
‫‪𝑖−3‬‬
‫‪32‬‬
‫הפונקציה הנ"ל יוצרת‪ ,‬למשל‪ ,‬את הסדרה‬
‫…‪1,1,1,1,3,3,9,9,27,27,81,81,‬‬
Quicksort
‫‪ - Quicksort‬הרעיון‬
‫• שיטת הפרד ומשול‬
‫• בוחרים איבר במערך שיהיה ה‪ ,pivot-‬ומחלקים‬
‫את האיברים במערך לשתי קבוצות‪:‬‬
‫• )‪(< pivot) and (> pivot‬‬
‫)‪(> pivot‬‬
‫‪RIGHT group‬‬
‫)‪(<pivot‬‬
‫‪LEFT group‬‬
‫האלגוריתם‬
int partition( A, low, high )
pivot_value ← A[low]
left ← low
pivot ← left
right ← high
while ( left < right )
// Move left while item < pivot
while( left < high && A[left] ≤ pivot_value)
left++
// Move right while item > pivot
while( A[right] > pivot_value)
right—
// Make sure right has not passed left
if( left < right )
SWAP(A, left, right)
// right is final position for the pivot
A[low] ← A[right]
A[right] ← pivot_item
return right
quickSort( A, low, high )
if(high > low)
pivot ← partition(A, low, high)
quickSort(A, low, pivot-1 )
quickSort(A, pivot+1, high)
‫ביצוע מיון לכל המערך יתבצע ע"י‬
‫הקריאה‬
quickSort(A, 0, length(A)-1)
‫דוגמה‬
4
1
7
3
8
6
2
Left
Pivot
// Move left while item < pivot
while( left < high && A[left] ≤ pivot_value)
left++
5
9 10
Right
‫דוגמה‬
4
1
7
3
8
6
2
Pivot Left
// Move left while item < pivot
while( left < high && A[left] ≤ pivot_value)
left++
5
9 10
Right
‫דוגמה‬
4
Pivot
1
7
3
8
6
2
Left
// Move left while item < pivot
while( left < high && A[left] ≤ pivot_value)
left++
5
9 10
Right
‫דוגמה‬
4
Pivot
1
7
3
8
6
Left
// Move right while item > pivot
while( A[right] > pivot_value)
right--
2
5
9 10
Right
‫דוגמה‬
4
Pivot
1
7
3
8
6
Left
// Move right while item > pivot
while( A[right] > pivot_value)
right--
2
5
Right
9 10
‫דוגמה‬
4
Pivot
1
7
3
8
6
Left
// Move right while item > pivot
while( A[right] > pivot_value)
right--
2
Right
5
9 10
‫דוגמה‬
4
Pivot
1 7
Left
3
8
6 2
5
9 10
Right
if( left < right ) \\Make sure right has not passed left
SWAP(A, left, right)
‫דוגמה‬
4
Pivot
1
2
3
Left
8
6
7
Right
// Move left while item < pivot
while( left < high && A[left] ≤ pivot_value)
left++
5
9 10
‫דוגמה‬
4
Pivot
1
2
3
8
Left
6
7
Right
// Move left while item < pivot
while( left < high && A[left] ≤ pivot_value)
left++
5
9 10
‫דוגמה‬
4
Pivot
1
2
3
8
6
Left Right
// Move right while item > pivot
while( A[right] > pivot_value)
right--
7
5
9 10
‫דוגמה‬
4
Pivot
1
2
3
8
6
Left
Right
// Move right while item > pivot
while( A[right] > pivot_value)
right--
7
5
9 10
‫דוגמה‬
4
Pivot
1
2
3
8
6
Right Left
// Move right while item > pivot
while( A[right] > pivot_value)
right--
7
5
9 10
‫דוגמה‬
4
Pivot
1
2
3 8 6 7 5 9 10
Right Left
// right is final position for the pivot
A[low] ← A[right]
A[right] ← pivot_value
return right
‫דוגמה‬
‫‪4‬‬
‫‪9 10‬‬
‫‪5‬‬
‫‪7‬‬
‫‪6‬‬
‫‪8‬‬
‫‪9 10‬‬
‫‪5‬‬
‫‪7‬‬
‫‪6‬‬
‫‪8‬‬
‫‪2‬‬
‫‪9 10‬‬
‫‪8‬‬
‫‪7‬‬
‫‪6‬‬
‫‪5‬‬
‫‪...‬‬
‫‪3‬‬
‫‪2‬‬
‫‪9 10‬‬
‫‪8‬‬
‫‪7‬‬
‫‪6‬‬
‫‪5‬‬
‫‪3‬‬
‫‪2‬‬
‫‪4‬‬
‫‪2‬‬
‫‪1‬‬
‫‪3‬‬
‫‪1‬‬
‫‪3‬‬
‫‪1‬‬
‫‪1‬‬
‫?‪Why Quicksort‬‬
‫• זמן ריצה‪:‬‬
‫במקרה הגרוע – )‪O(n^2‬‬
‫במקרה הממוצע ‪O(nlogn) -‬‬
‫למה משתמשים בו בפועל ולא ב‪ merge-sort‬שמבטיח ריצה‬
‫בזמן )‪?O(nlogn‬‬
‫ראיתם בכיתה‪ ,‬כי בפועל זמן הריצה קרוב לזה של המקרה‬
‫הטוב‪ .‬הקבועים ב‪ Quicksort-‬קטנים מאלו שב‪merge-sort-‬‬
‫למשל‪ ,‬ולכן ברוב המקרים ירוץ מהר יותר‪.‬‬
‫היתרון הגדול של ‪ Quicksort‬שזהו אלגוריתם ‪ in place‬והוא לא‬
‫דורש זיכרון נוסף‪ ,‬לעומת ‪ merge-sort‬המקצה מערכים‬
‫נוספים‪.‬‬
‫‪in place algorithms: need small, constant amount of‬‬
‫‪extra storage space, beyond the items being sorted.‬‬
Quicksort
• stable sorting algorithms: maintain the
relative order of records with equal keys
• Is the QuickSort version above stable?
– No
‫שאלה ‪3‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫נתונה קבוצה של ‪ n‬איברים ‪ ,S‬בה אותו איבר יכול‬
‫להופיע יותר מפעם אחת‪ ,‬ואינדקס ‪.(1 ≤ k ≤ n( k‬‬
‫האיבר ה‪ k-‬בגודלו הוא האיבר שיימצא במקום ה‪k-‬‬
‫אם נמיין את האיברים‪.‬‬
‫הציעו אלגוריתם שמוצא את האיבר ה‪ k-‬בגודלו ב‪-‬‬
‫)‪ O(n‬זמן בממוצע‪.‬‬
‫לדוגמה‪{6, 3, 2, 4, 1, 1, 2, 6} :‬‬
‫האיבר ה‪ 4-‬בגודלו הוא ‪ 2‬מכיוון שהוא נמצא‬
‫במיקום ‪ 4‬בקבוצה הממוינת‪:‬‬
‫}‪.{1, 1, 2, 2, 3, 4, 6, 6‬‬
‫ פתרון‬- 3 ‫שאלה‬
Select(k, S) // returns k-th element in S.
pick x in S
partition S into: // Slightly different variant of partition()
max(L) < x, E = {x}, x < min(G)
if k ≤ length(L) // Searching for item ≤ x.
return Select(k, L)
else if k ≤ length(L) + length(E) // Found
return x
else // Searching for item ≥ x.
return Select(k - length(L) - length(E), G)
pivot ,‫ בגודלו‬k-‫ – האיבר ה‬x
:‫ קבוצות‬3-‫ ל‬S ‫בכל שלב מחלקים את‬
x-‫ כל האיברים הגדולים מ‬-G
x-‫ כל האיברים הקטנים מ‬-L
x-‫ כל האיברים השווים ל‬-E
G-‫ או ב‬L-‫ ממשיכים לחפש אותו רקורסיבית ב‬,x ‫אם לא מצאנו את‬
‫שאלה ‪ - 3‬פתרון‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫במקרה הגרוע‪:‬‬
‫ה‪ pivot-‬הנבחר ‪ x‬הוא האיבר המקסימלי במערך הנוכחי‪ ,‬ויש‬
‫רק אחד כזה‪.‬‬
‫‪ – G‬קבוצה ריקה‪|L|=n-1 ,|E|=1 ,‬‬
‫𝑛 𝑂‪𝑇 𝑛−1 +‬‬
‫𝑘>𝑛‬
‫= 𝑛 𝑇‬
‫𝑘‬
‫𝑘=𝑛‬
‫פתרון נוסחת הנסיגה‪𝑇 𝑛 = 𝑂(𝑛2 ) :‬‬
‫במקרה הממוצע‪:‬‬
‫בדומה ל‪ ,Quicksort-‬חצי מהאיברים ב‪ S-‬הם טובים כ‪ ,pivot-‬לכן‬
‫‪3‬‬
‫הגודל של הממוצע ‪ G‬ו‪ L-‬יהיה קטן מ 𝑛‬
‫• )𝑛(𝑂 = 𝑛 𝑂 ‪+‬‬
‫‪3‬‬
‫𝑛‬
‫‪4‬‬
‫‪4‬‬
‫𝑇 ≤ 𝑛 𝑇 )שיטת המאסטר(‬
‫שאלה ‪4‬‬
‫• במערך בגודל ‪ ,n‬הציעו אלגוריתם בזמן צפוי של‬
‫)‪ O(n‬שקובע האם קיים מספר שמופיע יותר מ ‪n/2‬‬
‫פעמים‬
‫שאלה ‪4‬‬
‫• במערך בגודל ‪ ,n‬הציעו אלגוריתם בזמן צפוי של‬
‫)‪ O(n‬שקובע האם קיים מספר שמופיע יותר מ ‪n/2‬‬
‫פעמים‬
‫• אם ‪ x‬מופיע יותר מ ‪ ,n/2‬אז הוא המספר ה‬
‫‪ 𝑛/2 + 1‬בגודלו במערך‬
‫שאלה ‪4‬‬
‫שאלה ‪5‬‬
‫• הציעו אלגוריתם למיון בזמן )‪ O(n‬במקרה הגרוע‬
‫במקרה הבא (בלי תוספת זכרון)‪:‬‬
‫‪ .1‬כל המפתחות הם ‪ 0‬או ‪1‬‬
‫נבצע ‪ Partition‬עם ‪pivot=0‬‬
‫שאלה ‪5‬‬
‫• הציעו אלגוריתם למיון בזמן )‪ O(n‬במקרה הגרוע‬
‫במקרה הבא (בלי תוספת זכרון)‪:‬‬
‫‪ .2‬כל המפתחות הם בטווח ]‪ k( [1..k‬קבוע)‬
‫נבצע ‪ Partition‬עם ‪pivot=1‬‬
‫נבצע ‪ Partition‬עם ‪pivot=2‬‬
‫‪...‬‬
‫נבצע ‪ Partition‬עם ‪pivot=k-1‬‬
‫שאלה ‪6‬‬
‫• נתון אלגוריתם מיון חדש‪:‬‬
‫– )]‪Sort recursively the first 2/3 of A (A[1..2n/3‬‬
‫– )]‪Sort recursively the last 2/3 of A (A[n/3..n‬‬
‫– )]‪Sort recursively the first 2/3 of A (A[1..2n/3‬‬
‫‪2‬‬
‫‪3‬‬
‫• אם ‪ ∗ n‬הוא לא מספר שלם אז נעגל אותו‬
‫למעלה‪.‬‬
‫• הוכיחו את האלגוריתם הנ"ל (כלומר‪ ,‬להסביר‬
‫שהוא עובד) והראו את זמן הריצה‪.‬‬
‫שאלה ‪6‬‬
‫– )]‪Sort recursively the first 2/3 of A (A[1...2n/3‬‬
‫– )]‪Sort recursively the last 2/3 of A (A[n/3...n‬‬
‫– )]‪Sort recursively the first 2/3 of A (A[1...2n/3‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫הוכחה‪:‬‬
‫לאחר הצעד הראשון ‪ 1/3‬האיברים הגדולים ביותר במערך‬
‫נמצאים ב‪ 2/3‬המקומות האחרונים במערך‪.‬‬
‫לכן‪ ,‬לאחר הצעד השני ‪ 1/3‬האיברים האחרונים גדולים‬
‫מיתר האיברים במערך‪ ,‬והם ממוינים (בינם לבין עצמם)‬
‫כלומר‪ 1/3 ,‬האיברים האחרונים הם הגדולים ביותר ויהיו‬
‫ממוינים במקומם‪.‬‬
‫לאחר מכן אנחנו ממיינים את ‪ 2/3‬האיברים הנותרים‪ ,‬ולכן‬
‫אנחנו מקבלים מערך ממוין‪.‬‬
6 ‫שאלה‬
Sort recursively the first 2/3 of A (A[1..2n/3]) –
Sort recursively the last 2/3 of A (A[n/3+1..n]) –
Sort recursively the first 2/3 of A (A[1..2n/3]) –
2𝑛
𝑇 𝑛 = 3𝑇
:‫זמן ריצה‬
3
:‫נפתח בשיטת האיטרציה‬
• 𝑇 𝑛 = 3𝑇
2𝑛
3
= 3 3𝑇
8𝑛
3 3 3𝑇
27
4𝑛
9
•
•
=
2
3
𝑖
= … = 3𝑇
𝑖
𝑛
:‫ = 𝑖 צעדים‬log 2 𝑛 ‫אחרי‬
•
3
log3 𝑛
𝑇 𝑛 = 3
2
·𝑇 1 =⋯=𝑛
)‫𝑛 𝑂 = 𝑛 𝑇 (ניתן להגיע לזה גם בעזרת שיטת המאסטר‬
log3 3
log3 3
2
2
•
‫לכן‬
•
‫שאלה ‪7‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫נתון מערך ‪ A‬עם ‪ M+N‬איברים‪ N .‬האיברים‬
‫הראשונים ממויינים‪ ,‬ו ‪ M‬האיברים האחרונים אינם‬
‫ממויינים‪.‬‬
‫מהו זמן הריצה במונחים של ‪ M,N‬במקרה הגרוע‬
‫אם מבצעים מיון הכנסה (‪ )insertion sort‬על ‪?A‬‬
‫פתרון‪:‬‬
‫בעצם צריך לבצע הכנסה רק ל‪ M‬האיברים‬
‫האחרונים‪ .‬לכל אחד מהם לוקח 𝑀 ‪ 𝑂 𝑁 +‬לכן‬
‫סה"כ 𝑀 ‪.𝑂 𝑀 𝑁 +‬‬
‫שאלה ‪7‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫נתון מערך ‪ A‬עם ‪ M+N‬איברים‪ N .‬האיברים‬
‫הראשונים ממויינים‪ ,‬ו ‪ M‬האיברים האחרונים אינם‬
‫ממויינים‪.‬‬
‫מהו זמן הריצה במונחים של ‪ M,N‬במקרה הגרוע אם‬
‫מבצעים מיון הכנסה (‪ )insertion sort‬על ‪?A‬‬
‫פתרון נוסף‪:‬‬
‫ניתן לבצע ‪ insertion sort‬ל‪ M‬האיברים האחרונים‬
‫בזמן ‪ 𝑂 𝑀2‬ואז לבצע איחוד בזמן 𝑀 ‪𝑂 𝑁 +‬‬
‫• סה"כ זמן ריצה 𝑁 ‪= 𝑂 𝑀2 +‬‬
‫𝑁 ‪𝑂 𝑀2 + 𝑀 +‬‬
‫שאלה ‪7‬‬
‫• נתון מערך עם ‪ M+N‬איברים‪ N .‬האיברים הראשונים‬
‫ממויינים‪ ,‬ו ‪ M‬האיברים האחרונים אינם ממויינים‪.‬‬
‫• עבור כל אחד מהמקרים הבאים הציעו שיטה (או שילוב של‬
‫שיטות) למיון יעיל בזמן הגרוע‪.‬‬
‫‪M=O(1) (a‬‬
‫• מיון הכנסה ב )‪O(N‬‬
‫שאלה ‪7‬‬
‫• נתון מערך עם ‪ M+N‬איברים‪ N .‬האיברים הראשונים‬
‫ממויינים‪ ,‬ו ‪ M‬האיברים האחרונים אינם ממויינים‪.‬‬
‫• עבור כל אחד מהמקרים הבאים הציעו שיטה (או שילוב של‬
‫שיטות) למיון יעיל בזמן הגרוע‪.‬‬
‫‪M=O(logN) (b‬‬
‫• מיין את ‪ M‬ב‪O(MlogM) – merge sort‬‬
‫• אחד (‪ )merge‬את שני החלקים – )‪O(M+N‬‬
‫• סה"כ זמן ריצה 𝑀 ‪𝑂 𝑀 log 𝑀 + 𝑀 + 𝑁 = 𝑂(𝑀 log‬‬
‫𝑁 𝑂 =𝑁 ‪+‬‬
‫שאלה ‪7‬‬
‫• נתון מערך עם ‪ M+N‬איברים‪ N .‬האיברים‬
‫הראשונים ממויינים‪ ,‬ו ‪ M‬האיברים האחרונים אינם‬
‫ממויינים‪.‬‬
‫• עבור כל אחד מהמקרים הבאים הציעו שיטה (או‬
‫שילוב של שיטות) למיון יעיל בזמן הגרוע‪.‬‬
‫‪M=O(N) (c‬‬
‫• מיין את כל המערך ב‪O(NlogN) – merge sort‬‬
‫• הזמן של ‪ quicksort‬במקרה הגרוע יהיה )‪,O(N2‬‬
‫ולכן לא נשתמש בו‬
‫שאלה ‪8‬‬
‫• הציעו שיטה להפוך אלגוריתם מיון מבוסס השוואות לא יציב‬
‫‪ A‬לאלגוריתם יציב ’‪.A‬‬
‫• פתרון‪:‬‬
‫• לכל איבר נוסיף את האינדקס שלו כך שיהיו זוג‬
‫)‪.(key,index‬‬
‫• מיין את האיברים לפי‪:‬‬
‫‪[key1, index1] < [key2, index2] ⇔ key1 < key2 or‬‬
‫)‪( key1 = key2 and index1 < index2‬‬
‫‪[key1, index1] > [key2, index2] ⇔ key1 > key2 or‬‬
‫)‪(key1 = key2 and index1 > index2‬‬
‫• הוספנו 𝑛 𝑂 זיכרון וזמן הריצה נשאר זהה לשל‬
‫האלגוריתם ‪.A‬‬
‫שאלה ‪8‬‬
‫• הציעו שיטה להפוך אלגוריתם מיון מבוסס השוואות‬
‫לא יציב ‪ A‬לאלגוריתם יציב ’‪.A‬‬
‫• פתרון נוסף‪:‬‬
‫‪ .1‬נוסיף לכל איבר את האינדקס שלו‪.‬‬
‫‪ .2‬נריץ את אלגוריתם ‪ A‬הרגיל על המפתחות‪.‬‬
‫‪ .3‬לכל איבר המופיע יותר מפעם אחת נריץ מיון נוסף‬
‫הפעם לפי האינדקס‪.‬‬
‫• זמן ריצה ‪ :‬שלב ‪ – 3‬במקרה הגרוע אותו איבר מופיע‬
‫בכל התאים ולכן זמן הריצה הוא 𝑛 ‪𝑂 𝑛 log‬‬
‫סה"כ זמן הריצה )𝑛 ‪𝑂(𝑛 log‬‬