המצגת נטענת. אנא המתן

המצגת נטענת. אנא המתן

תרגול מס' 7: Memoization Quicksort תרגילים מתקדמים ברקורסיה

מצגות קשורות


מצגת בנושא: "תרגול מס' 7: Memoization Quicksort תרגילים מתקדמים ברקורסיה"— תמליל מצגת:

1 תרגול מס' 7: Memoization Quicksort תרגילים מתקדמים ברקורסיה

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

3 חישוב המספר ה-n בסדרה: public class Fib {
public static int fib(int n){ int ans; if (n==0) ans = 0; else if (n==1) ans = 1; else ans = fib(n-1)+fib(n-2); return ans; } public static void main(String[] args){ int n = 20; System.out.println("fib("+n+") = "+fib(n)); רקורסית זנב? לא!

4 Memoization (without ‘r’)
ברישום הבא, מובא עץ הקריאות לפונקציה כאשר ניתן לראות כי ישנם מספר חישובים שמתבצעים יותר מפעם אחת (אלו המודגשים בצבע): fib(5) fib(3) fib(1) fib(2) fib(0) fib(4)

5 ניתן לחסוך את החישובים המיותרים ע"י שמירת תוצאות של חישובים שבוצעו:
נשמור תוצאות ביניים ב lookup table-כך שחישוב יתבצע פעם אחת לכל היותר. לכל ערך שנרצה לחשב, נבדוק תחילה האם ערך זה חושב, כלומר, האם יש עבורו ערך מתאים ב lookup table. אם כן, נשתמש בערך זה. אחרת, נבצע את החישוב ונשמור את התוצאה בכניסה המתאימה בטבלה. הערכים נשמרים בטבלה לפי הקלט. כלומר, לכל קלט אפשרי יש כניסה מתאימה בטבלה.

6 דוגמא בכדי ליעל את fib נשתמש בטכניקת הmemoization לשמירת תוצאות החישובים שבוצעו. נראה תוכנית המחשבת את האיבר ה n-י בסדרת פיבונאצ'י, ומשתמשת בטכניקה זו לשמירת תוצאות של חישובים רקורסיביים. במקרה זה ה lookup table הינה מערך חד מימדי, כך שהתא בעל אינדקס i במערך, מכיל את הערך עבור fib(i). באם ערך זה עדיין לא חושב, יכיל תא זה את הערך 1-.

7 והפתרון: public class FibMemo{ פונקציה עוטפת
public static int fib(int[] lookupTable, int n) { if (n==0) lookupTable[n]= 0; if (n==1) lookupTable[n]= 1; if (lookupTable[n]==-1)//EMPTY lookupTable[n] = fib (lookupTable,n-1) + fib(lookupTable,n-2); return lookupTable[n]; } פונקציה עוטפת public static int fib(int n) { int[] lookupTable = new int[n+1]; for (int i=0; i < lookupTable.length ; i=i+1){ lookupTable[i] = -1; //EMPTY } return fib(lookupTable, n);

8 Memoization כעת עץ הקריאות לפונקציה יראה כך: fib(5) fib(3) fib(1)

9 Divide-and-Conquer טכניקת ה Divide-and-Conquer מבוססת על רעיון דומה לפתרון רקורסיבי של בעיות: חלק את הבעיה המקורית לתתי בעיות קטנות (שניים או יותר) - Divide פתור כל תת בעיה – Conquer צרף את תתי הפתרונות לפתרון לבעיה המקורית. ישנם אלגוריתמים רבים המתוכננים לפי עיקרון זה, עליהם נמנים האלגוריתמים הבאים: Mergesort (נלמד בהרצאות) Quicksort

10 תזכורת: חציון תזכורת: חציון הוא מדד למיקום המרכז של קבוצת נתונים מספריים. לדוגמא: החציון של קבוצת המספרים 1, 2, 22, 7, 19, 8, 16 הוא 8 מכיוון ש: 1, 2, 7, 8, 16, 19, 22

11 מיון מהיר (Quick Sort) חלוקת המערך לשני חלקים לפי ציר (pivot) שנבחר מחדש בכל שלב של הרקורסיה ומיון רקורסיבי של כל צד נרצה שהציר הנבחר יהיה הערכה (או ניחוש) של החציון במערך לצורך פישוט הבעיה בקוד שלנו נבחר את האיבר הראשון כציר.

12 מיון מהיר (Quicksort) - דוגמא
4 17 21 12 3 9 1 15 6 1 3 4 12 9 17 21 15 3 1 9 12 21 17 3 9 21 4 3 1 6 12 9 15 21 17 12

13 הבהרות אם נוכל להבטיח כי בכל שלב נבצע את השינוי על המערך עצמו ללא יצירת מערך חדש יתקיים שבסוף הריצה לאחר כל החלוקות המערך שלנו יהיה ממוין

14 מיון מהיר – הקוד public class QuickSort { //….
public static void quicksort(int[] arr, int start, int end){ if (start<end){ int i = partition(arr, start, end); quicksort(arr, start, i-1); quicksort(arr, i+1, end); } public static void quicksort(int[] arr){ quicksort(arr, 0, arr.length-1); }

15 מימוש פונקציית partition
ברצוננו לממש פונקציה אשר מקבלת מערך ומשנה את המערך כך שקודם כל יופיעו כל המספרים הקטנים (או שווים) לאיבר הראשון לאחר מכן האיבר הראשון ולבסוף המספרים הגדולים מהאיבר הראשון. 4 17 21 12 3 9 1 15 6 קלט: 15 17 21 12 9 6 1 4 3 פלט:

16 מיון מהיר – partition public static int partition(int[] arr, int start, int end){ int pivot = arr[start]; int i = start; int j = end; while(i<j){ while(i<end && arr[i] <= pivot) //scan upwards i=i+1; while(arr[j] > pivot) //scan downwards j=j-1; if (i<j) swap(arr,i,j); } swap(arr,start,j); //put pivot in place return j;

17 דוגמאת ריצה של partition
pivot pivot Swap! 4 17 21 12 3 9 1 15 6 15 17 21 12 9 6 1 4 3 15 17 21 12 9 3 1 4 6 15 17 21 12 3 9 1 4 6 start i i i j i i j j j j end j

18 מיון מהיר – פונקציות עזר
public static void initRandomArray(int[] arr){ // shuffle the array arr int n = arr.length; for (int i = 0; i < n; i++) { arr[i] = (int) (Math.random() * 10 * n); } public static void printArray (int[] arr) { for (int i=0; i<arr.length; i=i+1) System.out.print (arr[i]+" "); System.out.println(); public static void swap(int[] arr, int i, int j){ // swap arr[i] and arr[j] int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;

19 מיון מהיר – הקוד (המשך) import java.util.Scanner;
public class QuickSort { public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("Enter number of elements to sort:"); int n = sc.nextInt(); int[] arr = new int[n]; // Initializes arr with random numbers // in [0..10*N) initRandomArray(arr); System.out.println("The input array:"); printArray(arr); quicksort(arr); System.out.println("The sorted array:"); } //…. continued

20 Quicksort Example Example:
Video:

21 הדפסת המחרוזות באורך n בהינתן מספר מספר n 0 ≤, נרצה להחזיר מערך של 2n המחרוזות באורך n המורכבות מאפסים ואחדים. סדר המחרוזת הוא סדר המניה מאפס ל 2n-1 בבסיס 2. הפלט עבור n=0: {“”} הפלט עבור n=1: {“0”,”1”} הפלט n=2: {“00”,”01”,”10,”11”} הפלט עבור n=3: {“000”,”001”,”010”,”011”,“100”,”101”,”110”,”111”}

22 השלימו את הפונקציה public static String[] binaryNums(int n){
String[] answer; if (n==0){ answer = new String[1]; answer[0]=""; } else { // // Your code here } return answer; 22 22

23 הרעיון של הרקורסיה n=3 n=2 n=1 n=0 “”

24 רעיון של הרקורסיה n=3 n=2 “0” + “” “1” + “” n=1 1 n=0 “”

25 רעיון של הרקורסיה n=3 n=2 00 01 10 11 n=1 1 n=0 “”

26 רעיון של הרקורסיה n=3 000 001 010 011 100 101 110 111 n=2 11 01 00 10 n=1 1 n=0 “”

27 הקוד public static String[] binaryNums(int n) { String[] answer;
if (n==0){ answer = new String[1]; answer[0]=""; } else { String[] prev = binaryNums(n-1); answer = new String[2*prev.length]; for (int i =0;i<prev.length; i = i+1) { answer[i]= "0" + prev[i]; answer[prev.length + i] = "1“+ prev[i]; } return answer; 27 27

28 הדפסת הפרמוטציות של מחרוזת
פרמוטציה של מחרוזת מוגדרת כמחרוזת המכילה את אותן אותיות, ייתכן שבשינוי סדר. נניח בדוגמה זו שכל האותיות שונות זו מזו. למשל הפרמוטציות עבור המחרוזת bcd הם: “bcd" “bdc" “cbd“ “cdb” “dbc“ “dcb”

29 הרעיון של הרקורסיה i=0 i=1 ““, “a” + “b” + “c” +”d” d, “a” + “b” + “c”
output: abcd i=0 cd, “a” + “b” cd, “a” + “b” i=0 bcd, “a” bcd, “a” נרוץ עם i מ0 עד גודל המחרוזת ועבור כל i נבחן את כל המחרזות האפשריות בהן התו הi הוא הראשון כך שבכל קריאה i הוא האינדקס של האות הבאה אותה מצרפים למחרוזת i=0 abcd,”” abcd,””

30 הרעיון של הרקורסיה i=1 ““, “a” + “b” + “c” +”d” d, “a” + “b” + “c”
output: abcd i=0 i=1 cd, “a” + “b” cd, “a” + “b” i=0 bcd, “a” bcd, “a” i=0 abcd,”” abcd,””

31 הרעיון של הרקורסיה ““, “a” + “b” + “c” +”d” d, “a” + “b” + “c” output:
i=1 i=2 cd, “a” + “b” cd, “a” + “b” “”, “a” + “b” + “d” + “c” i=0 c, “a” + “b” + “d” output: abdc bcd, “a” bcd, “a” i=0 abcd,”” abcd,””

32 הרעיון של הרקורסיה ““, “a” + “b” + “c” +”d” d, “a” + “b” + “c” output:
i=1 cd, “a” + “b” cd, “a” + “b” i=1 “”, “a” + “b” + “d” + “c” i=1 c, “a” + “b” + “d” output: abdc bcd, “a” bcd, “a” i=0 abcd,”” abcd,”” bd, “a” + “c” bd, “a” + “c” d, “a” + “c” + “b” output: acbd “”, “a” + “c” + “b” + “d”

33 הרעיון של הרקורסיה . . . . . . ““, “a” + “b” + “c” +”d”
d, “a” + “b” + “c” output: abcd cd, “a” + “b” cd, “a” + “b” “”, “a” + “b” + “d” + “c” i=3 c, “a” + “b” + “d” output: abdc bcd, “a” bcd, “a” abcd,”” abcd,”” bd, “a” + “c” bd, “a” + “c” d, “a” + “c” + “b” . . . bc, “a” + “d” output: acbd “”, “a” + “c” + “b” + “d” . . .

34 קוד הדפסת הפרמוטציות של מחרוזת
public static void perms(String s){ // We call the method perm(s,"") which prints // the empty string followed by each permutation // of s the empty string. perms(s,""); }

35 קוד הדפסת הפרמוטציות של מחרוזת
/** Function prints all the permutation of a string. * Note: assume the string is a set (no duplicate * chars) */ // Prints string acc followed by all permutations of // string s1 public static void perms(String s1, String acc){ if (s1.length()==0) System.out.println(acc); else for (int i=0; i<s1.length(); i=i+1) perms(delete(s1, i), acc +s1.charAt(i)); } אם יש זמן 35

36 פונק' עזר: delete // This function returns the string s with the i-th
// character removed public static String delete(String s, int i){ // Assumes that i is a position in the string return s.substring(0,i) s.substring(i+1,s.length()); } 36

37 הרכבת סכום נתון ממשקולות
בהינתן מערך משקולות אי-שליליים ומשקל נוסף (משקל סכום), נרצה לבדוק האם ניתן להרכיב מהמשקולות משקל השווה למשקל הסכום הנתון. דוגמא לקלט: weights={1,7,9,3} Sum = 12 במקרה זה הפונקציה תחזיר true כי ניתן לחבר את המשקולות 9 ו 3 ולקבל את הסכום 12. דוגמא לקלט: weights={1,7,9,3} Sum = 15 במקרה זה הפונקציה תחזיר false כי לא ניתן לחבר משקולות לקבלת הסכום 15.

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

39 תיאור פתרון - המשך פתרון זה קל להציג כפונקציה רקורסיבית , boolean calcWeights(int[] weights, int i, int sum ) הפונקציה מחזירה ערך אמת האם ניתן להרכיב את הסכום מבין קבוצת המשקולות שבתת המערך. הפרמטרים: weights – מערך המשקולות sum – הסכום שיש להרכיב מהמשקולות i – פרמטר נוסף הנחוץ עבור הרקורסיה. i הוא אינדקס במערך weights ויסמן את האיבר הנוכחי במערך עליו מתבצעת הקריאה הרקורסיבית.

40 i=0 50 [10,20,30] i=1 40 [10,20,30] 50 [10,20,30] i=2 20 [10,20,30] 40 [10,20,30] 30 [10,20,30] 50 [10,20,30] i=3 -10 [10,20,30] 20 [10,20,30] 10 [10,20,30] 40 [10,20,30] [10,20,30] 30 [10,20,30] 20 [10,20,30] 50 [10,20,30]

41 קוד calcWeights הארגומנט i נחוץ עבור הרקורסיה – אך אינו באמת חלק מהקלט של הבעיה. בקריאה הראשונה ל calcWeights ערכו הוא 0. לכן נוסיף פונקצית מעטפת עם חתימה פשוטה יותר. // An envelope function, without i argument // A simpler signature public static boolean calcWeights(int[] weights, int sum) { return calcWeights(weights , 0, sum); }

42 (המשך) public static boolean calcWeights(int[] weights, int i, int sum) { boolean res = false; if (sum == 0) res = true; else if (i == weights.length || sum < 0) res = false; else res = calcWeights(weights,i+1,sum-weights[i]) || calcWeights(weights,i+1,sum); return res; }

43 דוגמא אחרונה הפונקציה void subsetsSum(int[] weights, int sum) מקבלת מערך weights של משקולות (ערכים שלמים חיוביים) ומשקל שלם sum חיובי ומדפיסה את כל תתי הקבוצות של איברי המערך weights שסכומם sum. דוגמא עבור weights={1,2,3,4,5} ו sum=10, הפונקציה תדפיס: 1 4 5 2 3 5

44 דוגמא אחרונה שאלה זו דומה מאוד לשאלת הרכבת סכום נתון ממשקולות. נסו להשלים את הפונקציות לבד. public static void subsetsSum(int[] weights, int sum){ subsetsSum(________השלימו את החסר___); } public static void subsetsSum( ){ השלימו את החסר }

45 דוגמא אחרונה: פתרון public static void subsetsSum(int[] weights, int sum){ subsetsSum(weights, sum,0,””); } public static void subsetsSum(int[] weights, int sum, int index, String acc){ if(sum == 0) System.out.println(acc); else if (sum > 0 && index < weights.length){ subsetsSum(weights,sum-weights[index], index+1,acc + weights[index] + ' '); subsetsSum(weights,sum,index+1,acc); } 45 45


הורד את "ppt "תרגול מס' 7: Memoization Quicksort תרגילים מתקדמים ברקורסיה

מצגות קשורות


מודעות Google