מבוא לתכנות ב- JAVA תרגול 9
מה בתרגול דוגמאות מתקדמות ברקורסיה פרמוטציות N מלכות מיונים רקורסיביים מיון מיזוג מיון מהיר
הדפסת פרמוטציות של מחרוזת פרמוטציה של מחרוזת מוגדרת כמחרוזת המכילה את אותן אותיות, ייתכן שבשינוי סדר. נניח בדוגמה זו שכל האותיות שונות זו מזו. למשל הפרמוטציות עבור המחרוזת bcd הן: bcd" bdc" cbd cdb dbc dcb
הרעיון של הרקורסיה d, a + b + c, a + b + c + d output: abcd cd, a + b bcd, a abcd, 4
הרעיון של הרקורסיה d, a + b + c cd, a + b, a + b + c + d output: abcd, a + b + d + c bcd, a c, a + b + d output: abdc abcd, 5
הרעיון של הרקורסיה d, a + b + c cd, a + b, a + b + c + d output: abcd, a + b + d + c bcd, a c, a + b + d output: abdc abcd, bd, a + c d, a + c + b output: acbd, a + c + b + d 6
הרעיון של הרקורסיה d, a + b + c cd, a + b, a + b + c + d output: abcd, a + b + d + c bcd, a c, a + b + d output: abdc abcd, bd, a + c... bc, a + d d, a + c + b output: acbd..., a + c + b + d 7
קוד הדפסת הפרמוטציות של מחרוזת /** Function prints all the permutations 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 s, String acc){ if (s.length()==0) System.out.println(acc); else for (int i=0; i<s.length(); i++) perms(s.substring(0,i) + s.substring(i+1), acc + s.charat(i)); 8
קוד הדפסת הפרמוטציות של מחרוזת 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,""); 9
N מלכות יש למקם N מלכות על לוח שחמט בגודל N*N שאף אחת מהמלכות לא מאיימת על אף אחת מחברותיה כך מהלכים אפשריים של מלכה
N מלכות נכתוב פונקציה רקורסיבית שתנסה למקם מלכות על לוח עד אשר תמצא פתרון או שתחזיר שלא קיים פתרון רעיון: מקם מלכה בשורה הראשונה עבור לשורה הבאה: אם מצאת מקום שאינו מאויים הצב מלכה והמשך לשורה הבאה אחרת חזור לשורה הראשונה ושנה את מיקום המלכה המשיכו כך שורה אחרי שורה, בכל אחת, מצאו את המקום הראשון בשורה שלא מאויים על ידי המלכות מהשורות הקודמות. אם הגעתם לשורה שבה לא קיים מקום לא מאויים, חזרו לשורה הקודמת והציבו את המלכה במקום הבא שאינו מאויים באותה השורה. יש להמשיך בביצוע האלגוריתם )להתקדם ולסגת במידת הצורך( עד למילוי כל השורות
הרעיון מה מקרה הבסיס? מה הצעד הרקורסיבי? no
- פתרון מלכות N public static boolean solvenqueens(int[][] board, int i) { if (i == board.length){ return true; for(int j=0; j < board.length; j++){ if (issafe(board,i,j)){ board[i][j] = 1; if (solvenqueens(board,i+1)){ return true; else{ board[i][j] = 0; return false;
- פתרון מלכות N public static void solvenqueens(int n){ int[][] board = new int[n][n]; if (solvenqueens(board,0)){ printboard(board); else{ System.out.println("no soution");
- פתרון מלכות N public static boolean issafe(int[][] board, int i, int j) { //attacked by other in left diagonal for (int r = 1; j-r > -1 && i-r > -1; r++){ if (board[i-r][j-r] == 1){ return false; //attacked by other in right diagonal for (int r = 1; j+r < board.length && i-r > -1; r++){ if (board[i-r][j+r] == 1){ return false; // check if there is another queen in same column for (int r = 0; r < i; r++){ if (board[r][j] == 1){ return false; return true;
N מלכות בקריאה לפונקציה solvenqueens(4) הודפס למסך הפתרון הבא איזה מהמשפטים הבאים הוא נכון: א. אין פתרון ללוח 4*4 בפינה השמאלית כך שהמלכה בשורה הראשונה היא ב. האלגוריתם מחזיר רק פתרון אחד מתוך רבים. אם היינו בוחרים למקם אחרת את המלכות באלגוריתם, ייתכן שהיה מחוזר פתרון בו המלכה בשורה הראשונה היא בפינה השמאלית
מיון מיזוג אלגוריתם מיון רקורסיבי רעיון: חלק את המערך לשני חלקים מיין כל חלק באופן רקורסיבי מזג את שני החלקים למערך ממויין )בשיטת הפרד ומשול( אחד
דוגמא 99 6 86 15 58 35 86 4 0
דוגמא 99 6 86 15 58 35 86 4 0 99 6 86 15 58 35 86 4 0
דוגמא 99 6 86 15 58 35 86 4 0 99 6 86 15 58 35 86 4 0 99 6 86 15 58 35 86 4 0
דוגמא 99 6 86 15 58 35 86 4 0 99 6 86 15 58 35 86 4 0 99 6 86 15 58 35 86 4 0 99 6 86 15 58 35 86 4 0 4 0
דוגמא 99 6 86 15 58 35 86 0 4 Merge 4 0
דוגמא 6 99 15 86 35 58 0 4 86 99 6 86 15 58 35 86 0 4 Merge
דוגמא 6 15 86 99 0 4 35 58 86 6 99 15 86 35 58 0 4 86 Merge
דוגמא 0 4 6 15 35 58 86 86 99 6 15 86 99 0 4 35 58 86 Merge
דוגמא 0 4 6 15 35 58 86 86 99
איך ממזגים 2 מערכים ממויינים? נניח שאנו רוצים למזג את המערכים הממויינים A,B למערך ממויין C נשתמש ב 2 אינדקסים i,j )אחד לכל מערך( כל עוד i,j לא מצביעים על סיום המערכים: השווה את שני האיברים A[i] ו B[j] את הקטן מבין השניים הכנס למערך המיזוג קדם את האינדקס של האיבר שאנחנו מסתכלים עליו במערך ב- 1. אם אחד מהאינדקסים מצביע על סיום המערך בעוד השני לא נעתיק את כל יתר האיברים מהמערך השני אל C.
דוגמא - מיזוג X: Y: 3 10 23 54 1 5 25 75 Result:
דוגמא - מיזוג 3 10 23 54 5 25 75 X: Y: Result: 1
דוגמא - מיזוג 10 23 54 5 25 75 X: Y: Result: 1 3
דוגמא - מיזוג 10 23 54 25 75 X: Y: Result: 1 3 5
דוגמא - מיזוג X: Y: 23 54 25 75 Result: 1 3 5 10
דוגמא - מיזוג X: Y: 54 25 75 Result: 1 3 5 10 23
דוגמא - מיזוג X: Y: 54 75 Result: 1 3 5 10 23 25
דוגמא - מיזוג X: Y: 75 Result: 1 3 5 10 23 25 54
דוגמא - מיזוג X: Y: Result: 1 3 5 10 23 25 54 75
פונקצית מיון-מיזוג public static void mergesort(int[] arr) { mergesort(arr, 0, arr.length-1); private static void mergesort(int[] arr, int low, int high) { if (low < high) { int middle = (high + low) / 2; mergesort(arr, low, middle); mergesort(arr, middle + 1, high); merge(arr, low, middle, high);
פונקצית מיזוג merge private static void merge(int[] arr, int low, int middle, int high) { int i = low; int j = middle+1; int k = 0; int[] mergedarray = new int[high-low+1]; while (i <= middle && j <= high){ if (arr[i] < arr[j]){ mergedarray[k] = arr[i]; i++; else{ mergedarray[k] = arr[j]; j++; k++; for (int l = i ; l <= middle; l++){ mergedarray[k] = arr[l]; k++; for (int l = j ; l <= high; l++){ mergedarray[k] = arr[l]; k++; for (int l = low ; l <= high; l++){ arr[l] = mergedarray[l-low];
מיון מהיר חלוקת המערך לשני חלקים לפי ציר )pivot( שנבחר מחדש בכל שלב של הרקורסיה ומיון רקורסיבי של כל צד נרצה שהציר הנבחר יהיה הערכה החציון במערך לצורך פישוט הבעיה, הראשון כציר. )או ניחוש( של בקוד שלנו נבחר את האיבר
- מיון מהיר )Quicksort( דוגמא 6 15 1 9 3 12 21 17 4 4 3 1 15 21 17 9 12 1 3 12 9 17 21 3 9 21 1 3 4 6 9 12 15 17 21 40
פונקציה למיון מהיר public static void quicksort(int[] arr){ quicksort(arr, 0, arr.length-1); 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); 41
מימוש פונקציית partition כל שנותר הוא לממש את פונקציית.partition ברצוננו לממש פונקציה אשר מקבלת מערך ומשנה אותו כך שקודם כל יופיעו כל המספרים הקטנים או שווים לציר )האיבר הראשון(, לאחר מכן הציר, ולבסוף המספרים הגדולים מהציר. קלט : 4 6 15 1 9 3 12 21 17 3 4 1 6 9 12 21 17 פלט: 15 42
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 the pivot in place return j; 43