Presentation is loading. Please wait.

Presentation is loading. Please wait.

שאלות ממבחנים. 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©2 תרגיל 1: מטריצות כתבו פונקציהvoid Rotation(int in [N][N], int out [N][N]) אשר מקבלת שני.

Similar presentations


Presentation on theme: "שאלות ממבחנים. 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©2 תרגיל 1: מטריצות כתבו פונקציהvoid Rotation(int in [N][N], int out [N][N]) אשר מקבלת שני."— Presentation transcript:

1 שאלות ממבחנים

2 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©2 תרגיל 1: מטריצות כתבו פונקציהvoid Rotation(int in [N][N], int out [N][N]) אשר מקבלת שני מערכים: מערך in, בגודל N×N, הינו מערך קלט. מערך out, בגודל N×N, הינו מערך פלט שצריך למלא. מערך הפלט, out, יהיה סיבוב של מערך in בזוית של 90 מעלות בכיוון השעון. הנח כי בתוכנית הראשית N הוגדר ע"י define#. 90°

3 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©3 תרגיל 1 (המשך) לדוגמא, עבור N=6 ו-in: מערך הפלט out ימולא כלהלן: 675321 61410642 62115963 628201284 6352515105 6423018126 123456 24691012 369 1518 51015202530 71421283542 666666

4 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©4 תרגיל 1 – הגישה לפתרון כדי למלא מערך, מבצעים השמה לכל i ו-j: void Rotation(int in[][N], int out[][N]) { int i, j; for (i=0; i<N; i++) { for (j=0; j<N; j++) { out[i][j]=in[?][?]; } עכשיו נשאר רק למצוא את האינדקסים של in.

5 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©5 איך מוצאים אינדקסים של in? כדי למצוא את האינדקסים, כדאי להסתכל על דוגמא קטנה: האינדקס הראשון זהה בכל עמודה, כלומר לא תלוי ב-i. בכל שורה הוא מתחיל מ-2 וקטן ככל ש-j גדל, כלומר ניתן לבטא את ערכו כ-(2-j). במטריצה 4x4 הוא יתחיל מ-3, ב-5x5 הוא יתחיל מ-4, כלומר הנוסחה הכללית היא (N-1-j). in[0][0]in[0][1]in[0][2] in[1][0]in[1][1]in[1][2] in[2][0]in[2][1]in[2][2] in[2][0]in[1][0]in[0][0] in[2][1]in[1][1]in[0][1] in[2][2]in[1][2]in[0][2] 90° in out i: j:012 0 1 2 קל לראות שהאינדקס השני שווה ל-i.

6 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©6 תרגיל 1 - פתרון והתוצאה היא: void Rotation(int in[][N], int out[][N]) { int i, j; for (i=0; i<N; i++) { for (j=0; j<N; j++) { out[i][j]=in[N-1-j][i]; }

7 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©7 תרגיל 2, סעיף א: מערכים כתבו פונקציה OrderEvenOdd(int a[], int n) אשר מקבלת מערך a וגודלו n. ידוע כי n הוא זוגי, ובנוסף בדיוק מחצית מהאיברים במערך הם זוגיים (אין צורך לבדוק שאכן הקלט הוא כזה). הפונקציה מסדרת את איברי המערך כך שבמקומות הזוגיים מופיעים כל האיברים הזוגיים, ובמקומות האי-זוגיים מופיעים האיברים האי- זוגיים. לדוגמא: עבור המערך (n==8): פלט אפשרי הינו המערך כדלקמן: 01234567 7618-51327-4 01234567 2767 1318-5

8 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©8 איך פותרים? אם היינו יכולים להגדיר מערך עזר בגודל n החיים היו קלים. היינו יכולים: –למצוא את כל האיברים הזוגיים ולשים במערך עזר במקומות 0,2,4… –למצוא את כל האיברים האי זוגיים ולשים במערך עזר במקומות 1,3,5… –להעתיק את מערך העזר חזרה ל-a. אבל n הוא לא קבוע, לכן לא ניתן להגדיר מערך בגודל n! לכן הדרך היא לעשות כל פעם swap לשני איברים בתוך המערך שנמצאים במקומות לא נכונים. עוד דבר שיש לשים לב: במערך יש איברים שלילים, לכן כדי לבדוק אם איבר a[i] הוא אי זוגי יש להשתמש בתנאי: (a[i] % 2 == 1) || (a[i] % 2 == -1)

9 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©9 האלגוריתם כל עוד במערך יש איברים שנמצאים במקום לא נכון בצע: –מצא את האיבר הזוגי הראשון שנמצא במקום אי זוגי –מצא את האיבר האי זוגי הראשון שנמצא במקום זוגי –בצע swap בין שני המספרים -4721367 -518 76543210 i_oddi_even

10 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©10 תרגיל 2 – פונקציית עזר void swap(int *x, int *y) { int tmp = *x; *x = *y; *y = tmp; }

11 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©11 תרגיל 2 – פתרון סעיף א' void OrderEvenOdd(int a[], int n) { int i_odd=0, i_even=1; while ((i_odd < n) && (i_even < n)) { while ((i_even < n) && ((a[i_even]%2 == 1) || (a[i_even]%2 == -1))) { i_even += 2; } while ((i_odd < n) && (a[i_odd]%2 == 0)) { i_odd += 2; } if ((i_odd < n) && (i_even < n)) { swap(&a[i_odd], &a[i_even]); } } } מחפשים איבר זוגי במקום אי זוגי מחפשים איבר אי זוגי במקום זוגי אם מצאנו שני איברים שלא במקומות שלהם – עושים swap עוברים על איברי המערך מהתחלה ועד הסוף חשוב לבדוק שלא גלשנו מגבולות המערך!

12 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©12 תרגיל 2, סעיף ב: מיון כתבו פונקציה (int a[ ], int n)SortEvenOdd אשר מקבלת מערך a וגודלו n. גם בסעיף הזה ידוע כי n הוא זוגי, ובנוסף בדיוק מחצית מהאיברים במערך הם זוגיים (גם כאן אין צורך לבדוק שאכן הקלט הוא כזה). הפונקציה ממיינת את איברי המערך כך ש: –האיברים הזוגיים יופיעו במקומות הזוגיים ממוינים בסדר לא יורד, –האיברים האי-זוגיים יופיעו במקומות האי-זוגיים ממוינים בסדר לא עולה. מותר להשתמש בפונקציה מהסעיף הקודם. לדוגמא: עבור המערך (n==8): הפלט הינו: 01234567 7618-51327-4 01234567 13276718-5

13 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©13 הדרך לפתרון אם נפעיל את הפונקציה מסעיף א' על המערך, איברים זוגיים יהיו במקומות זוגיים, ולהיפך. יישאר לנו: 1.למיין את האיברים במקומות הזוגיים בסדר לא יורד. 2.למיין את האיברים במקומות האי זוגיים בסדר לא עולה. אפשר למיין את האיברים ע"י מיון בועות שמסדר רק את האיברים במקומות הזוגיים/אי זוגיים.

14 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©14 תרגיל 2 – פתרון סעיף ב' void SortEvenOdd(int a[], int n) { int changed, i; OrderEvenOdd(a, n); changed = 1; while (changed) { changed = 0; for (i = 0; i < n-2; i += 2) { if (a[i] > a[i+2]) { swap(&a[i], &a[i+2]); changed = 1; } משתמשים בפונקציה מסעיף א' מיון בועות בסדר לא יורד אבל רק לאיברים במקומות זוגיים למה עד n-2 לא כולל?

15 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©15 תרגיל 2 – פתרון סעיף ב' (המשך) changed = 1; while (changed) { changed = 0; for (i = 1; i < n-1; i += 2) { if (a[i] < a[i+2]) { swap(&a[i], &a[i+2]); changed = 1; } מיון בועות בסדר לא עולה אבל רק לאיברים במקומות אי זוגיים

16 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©16 תרגיל 3: חיפוש כתבו פונקציה אשר מקבלת שני מערכים double a[ ] ו-double b[ ], מספר נוסף x ואת גודל המערכים n (לשניהם יש אותו הגודל). כל אברי מערך a[ ] שונים זה מזה וכל אברי מערך b[ ] שונים זה מזה. ידוע כי המערך a[ ] ממוין בסדר יורד ואילו המערך b[ ] ממוין בסדר עולה. הפונקציה תחזיר אינדקס i כך שמתקיים 2·a[i] – 3·b[i] = x. –אם לא קיים אינדקס כנ"ל, הפונקציה תחזיר -1. הנחיה: על הפונקציה להיות יעילה ככל הניתן. כלומר אסור לבצע חיפוש ליניארי במערכים.

17 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©17 הדרך לפתרון תזכורת: חיפוש ליניארי הינו חיפוש שעובר על כל איברי המערך אחד-אחד. חיפוש היותר יעיל הינו חיפוש בינארי, אך בשבילו צריכים מערך ממוין. נבדוק האם הביטוי2·a[i] – 3·b[i] מגדיר סדרה ממוינת של מספרים: –a ממוין בסדר יורד, לכן כאשר i גדל, a[i] קטן ומקטין את הביטוי. –b ממוין בסדר עולה, לכן כאשר i גדל, b[i] גדל ושוב מקטין את הביטוי (בגלל המינוס) –לכן הסדרה 2·a[i] – 3·b[i] ממוינת בסדר יורד: –לכן נשתמש בחיפוש בינארי על 2·a[i] – 3·b[i]. a:9541-2 b:-42378 2a - 3b:304-19-28

18 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©18 תרגיל 3 – פתרון int findIndex(double a[], double b[], int n, double x) { int low = 0, high = n-1, mid; double exp; while(low <= high) { mid = (low + high)/2; exp = 2*a[mid] - 3*b[mid]; if(exp == x) { return mid; } if(exp > x) { low = mid + 1; } else { high = mid - 1; } return -1; } זהו חיפוש בינארי עם שינוי קטן: במקום לחפש ערך של מערך מחפשים את expששווה ל-x האם אפשר היה לבנות מערך c[i]=2*a[i]-3*b[i] ולהשתמש בחיפוש בינארי בלי שינויים?

19 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©19 תרגיל 4: מחרוזות כתוב פונקציה המקבלת שתי מחרוזות s1 ו-s2 ומחזירה כמה פעמים s2 מופיע בתוך s1. על הפונקציה להיות case-insensitive, כלומר להתעלם מהבדל בגודל האותיות. מותר להשתמש ב-strlen ו-strcmp, עם include המתאים. אסור לשנות את המחרוזות s1 ו-s2. לדוגמא: עבור s2=“kAba 2 aBabABA$”ו- s1=“aBA” הפונקציה תחזיר 4.

20 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©20 הדרך לפתרון אי אפשר להשתמש ב-strcmp כי: –היא לא יודעת להשוות לתת מחרוזת שנמצאת באמצע מחרוזת. –היא case-sensitive. לכן נכתוב פונקציה מיוחדת שמתמודדת עם שני הדברים הללו. כדי לעבוד עם תת מחרוזת באמצע מילה, נעביר פרמטר int n המסמן את אורך המחרוזת שיש להשוות. כדי לבצע השוואה בלי חשיבות לגודל אותיות, נממש פונקציה מיוחדת להשוואה של שני תווים. מהי דרך קצרה לבדוק שני אותיות שווים? הרי יש ארבע אפשרויות: ‘A’ == ‘a’, ‘a’==‘A’, ‘a’ == ‘a’, ‘A’==‘A’ פתרון: נתרגם את שני האותיות לאותיות גדולות ואז נשווה עם "==".

21 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©21 תרגיל 4 – פתרון #include char UpCase(char c) { if (c >= 'a' && c <= 'z') { return c - 'a' + 'A'; } return c; } int IsEqualN(char s1[], char s2[], int n) { int i; for (i=0; i<n; i++) { if ( UpCase(s1[i]) != UpCase(s2[i]) ) { return 0; } } return 1; } תרגום של אות קטנה לאות גדולה, כל סימן שלא אות קטנה נשאר ללא שינוי. השוואה case-insensitive של n תווים ראשונים של שני מחרוזות.

22 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©22 תרגיל 4 – פתרון (המשך) int CountSubstring(char *s1, char *s2) { int len1 = strlen(s1), len2 = strlen(s2); int i, count = 0; for (i = 0; i <= len2-len1; i++) { if (IsEqualN(s1, s2+i, len1)) { count++; } return count; }

23 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©23 תרגיל 5: מערכים כתבו פונקציהvoid num2(int arr[ ], int len) –המקבלת מערך arr ואת אורכו len –ומדפיסה את צמד המספרים המופיע מספר פעמים הרב ביותר. –אם יש יותר מצמד אחד אזי יודפסו כל הצמדים. צמד מספרים הינם 2 מספרים הנמצאים במקומות עוקבים. הנח כי כל המספרים קטנים ממש מ- 500 וגדולים או שווים ל-0. דוגמא: עבור מערך 3 2 5 4 3 2 88 7 5 4 הצמדים הם:(4,5) (5,7) (7,88) (88,2) (2,3) (3,4) (4,5) (5,2) (2,3) לכן יודפס : 5 4 2 3 הערה: הסדר בתוך הצמד חשוב, כלומר: הצמד 4 5 שונה מהצמד 5 4.

24 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©24 הדרך לפתרון בשביל למצוא מהו צמד שמופיע הכי הרבה פעמים, צריכים לספור כמה פעמים מופיע כל צמד. כיוון שיש 500 אפשרויות לכל מספר במערך, יש 500*500 אפשרויות שונות של צמדים: –500 צמדים שהמספר הראשון שלהם 0 –500 צמדים שהמספר הראשון שלהם 1 –... –500 צמדים שהמספר הראשון שלהם 499 –סה"כ 500*500. כדי לספור את מספר הצמדים, נגדיר מטריצה m[500][500] שכל איבר m[i][j] סופר כמה פעמים הצמד (i,j) מופיע במערך arr.

25 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©25 תרגיל 5 – פתרון void num2( int arr[], int len ) { int m[500][500] = {0}; int i, j, max = 0; if ( len < 2 ) return; for ( i = 0 ; i < len-1 ; i++ ) m[arr[i]][arr[i+1]]++; for ( i = 0 ; i < 500 ; i++ ) for ( j = 0 ; j < 500 ; j++ ) if ( m[i][j] > max ) max = m[i][j]; for ( i = 0 ; i < 500 ; i++ ) for ( j = 0 ; j < 500 ; j++ ) if ( m[i][j] == max ) printf(“\n max appearance: %d, %d”, i, j ); } 1. נגדיר מטריצה 500*500 ונאתחל אותה באפסים. 2. נספור כמה פעמים מופיע כל צמד (arr[i], arr[i+1]) 3. נמצא את מקסימום של מספר ההופעות. 4. נדפיס את כל הצמדים שמספר ההופעות שלהם שווה למקסימום שמצאנו.

26 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©26 תרגיל 6: מטריצות ריבוע חצי-קסם הוא מערך דו-מימדי שבו סכומי השורות הם שווים. –(אין שום דרישה לגבי העמודות או האלכסונים) לדוגמה: מערך הבא: הוא ריבוע חצי-קסם, כיוון שסכום המספרים בכל שורה הוא 14. כתבו פונקציה int is_magic(int A[N][N]) המקבלת מערך דו מימדי ומחזירה 1 במידה וזהו ריבוע חצי-קסם, ואחרת מחזירה 0. יש להניח ש N מוגדר ב define#. 563 383 78

27 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©27 תרגיל 6 – פתרון int is_magic(int A[N][N]) { int curr_row_sum, i, j; int first_row_sum = 0; for (j=0; j<N; j++) } first_row_sum += A[0][j]; { for (i=1; i<N; i++) { curr_row_sum=0; for (j=0; j<N; j++) } curr_row_sum += A[i][j]; } if (curr_row_sum != first_row_sum) { return 0; } } return 1; } נחשב את הסכום של השורה הראשונה נבדוק שסכום של כל השורות שווה לסכום של השורה הראשונה נחשב את הסכום של השורה i אם הסכום שונה, זה לא ריבוע חצי-קסם. אין טעם לבדוק את שאר השורות. אם הגענו עד לכאן, סכום כל השורות שווה

28 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©28 תרגיל 7: מערכים כתוב פונקציה int sub_array ( int a[ ], int n, int *p ) –אשר מקבלת מערך a בגודל n –ומוצאת את תת-המערך הממוין בסדר לא יורד הארוך ביותר. הפונקציה מחזירה את גודלו של תת-מערך זה (זהו הערך המוחזר), וכן, באמצעות המצביע p, את אינדקס האיבר הראשון שלו. לדוגמא: אם המערך הוא:7 6 3 5 9 12 11 17 20 8 –אזי תת-המערך הממוין הגדול ביותר הינו בגודל 4, –ובאמצעות p יוחזר האינדקס של האיבר המסומן בקו תחתון, כלומר 2. הערה: במידה שישנם שני (או יותר) תת-מערכים ממוינים גדולים ביותר בחר באחד מהם כרצונך.

29 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©29 הדרך לפתרון - אפשרות א דרך פשוטה (אך לא כל כך יעילה) היא לעשות דבר הבא: נשים לב שגודל המקסימלי של תת מערך ממוין הוא n. לכן אפשר להתחיל מלבדוק האם המערך כולו ממוין בסדר לא יורד. אם כן – מצאנו את המקסימים אם לא – נבדוק את כל תתי המערכים בגודל n-1. אם מצאנו אחד שממוין בסדר לא יורד – המקסימום הוא n-1. אם לא – נבדוק את כל תתי המערכים בגודל n-2. וכך הלאה... אם נגיע לבדיקה של תתי מערכים בגודל 1 – סיימנו, כי כל מערך בגודל 1 ממוין.

30 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©30 תרגיל 7 – פונקצית עזר נשים לב שהבדיקה "האם תת מערך ממוין בסדר לא יורד?" חוזרת על עצמה עבור תתי מערכים בגדלים שונים. לכן כדאי לממש פונקציית עזר ש: –מקבלת מערך וגודל –מחזירה 1 אם המערך ממוין בסדר לא יורד, ו-0 אחרת: int is_sorted(int arr[], int len) { int i; for (i = 0; i <= len-2; i++) { if (arr[i] > arr[i+1]) { return 0; } return 1; } למה i המקסימלי המותר הוא len-2? אם מצאנו שני איברים בסדר יורד, המערך לא ממוין בסדר לא יורד. אם הגענו עד לכאן, כל זוג איברים סמוכים נמצאים בסדר הנכון, לכן כל המערך ממוין בסדר לא יורד.

31 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©31 פתרון תרגיל 7 – אפשרות א int sub_array(int a[], int n, int *p) { int curSize, subArrStart; if (n <= 0) { *p = 0; return 0; } for (curSize = n; curSize >= 2; curSize--) { for (subArrStart=0; subArrStart<=n-curSize; ++subArrStart){ if (is_sorted(a + subArrStart, curSize)) { *p = subArrStart; return curSize; } } } *p = 0; return 1; } וידוי חוקיות הפרמטרים. בודקים את כל הגדלים מ-n ועד 2. עוברים על כל תתי מערכים בגודל curSize. אם מצאנו אחד ממוין – הוא המקסימום. אם הגענו עד לכאן, אין אפילו תת מערך בגודל 2 ממוין בסדר לא יורד, נחזיר את תת המערך הראשון בגודל 1.

32 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©32 הדרך לפתרון - אפשרות ב דרך יותר קשה אך גם יותר יעילה היא לבצע את הבדיקה במעבר אחד. נחזיק התחלה וגודל של תת מערך הכי ארוך ממוין בסדר לא יורד שמצאנו עד עכשיו. בנוסף נחזיק התחלה וגודל של תת מערך ממוין בסדר לא יורד הנוכחי. נעבור על כל איברי המערך שקיבלנו בפרמטר: –אם a[i+1] ≥ a[i], תת מערך הנוכחי עדיין ממוין בסדר לא יורד. –אם לא – נעדכן את המקסימים לפי הצורך, נעביר את המצביע של תת מערך הממוין הנוכחי ל-a[i+1] ונחזיר את גודל של המערך הנוכחי ל-1.

33 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©33 הדרך לפתרון - אפשרות ב 0123456789 76359121117208 ≥≤≥≥≥≤≤≤≤ i= curSize1 curStart0 maxSize1 maxStart0 234 1269 4 2 1231

34 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©34 פתרון תרגיל 7 – אפשרות ב int sub_array(int a[], int n, int *p) { int i, curSize = 1, curStart = 0, maxSize = 1, maxStart = 0; if (n <= 0) { *p = 0; return 0; } for (i=0; i<=n-2; i++) { if (a[i] <= a[i+1]) { curSize++; } else { if (maxSize < curSize) { maxSize = curSize; maxStart = curStart; } curStart = i+1; curSize = 1; } } if (maxSize < curSize) { maxSize = curSize; maxStart = curStart; } *p = maxStart; return maxSize; } וידוי חוקיות הפרמטרים. באיזה מקרה מטפלת הבדיקה מחוץ ללולאה?

35 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©35 תרגיל 8: מחרוזות בשאלה הבאה תצטרכו לכתוב קוד על שם יוליוס קיסר המשמש להצפנה ופענוח הודעות. בהינתן הודעה כלשהיא ומפתח שהינו מספר n אנו מצפינים את ההודעה ע"י החלפת כל אות באות עוקבת n צעדים אחריה. למשל: עבור המילה "grade" ומספר 2 נקבל "itcfg". –כי, למשל, i הינה 2 מקומות אחרי g הנחות: –n הינו מספר בין 0 ל- 25. –סדר האותיות ציקלי. למשל, אם תוסיפו 1 לאות z תקבלו את האות a. –בהודעה ישנן רק אותיות אנגליות קטנות (לכן אין רווחים).

36 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©36 תרגיל 8, סעיף א' כתבו פונקציה: void decrypt (char *Edata, int len, int n, char *data) המקבלת: –מערך תוויםEdata מוצפן, –אורכו len, –ומפתח n ומייצרת מחרוזת מפוענחת בתוך מערך data. הנח כי data הינו בעל גודל מספק. שים לב כי Edata אינו מסתיים ב- '\0' אלא נתון אורכו, וכי לא צריך להוסיף'\0' ל- data.

37 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©37 פתרון 8 סעיף א' #define LETTERS_NUM ('z'-'a'+ 1) /* 26 */ void decrypt(char *Edata, int len, int n, char *data) { int i; for (i = 0; i < len; i++) { data[i] = Edata[i] - n; if (data[i] < 'a') { data[i] += LETTERS_NUM ; } אם גלשנו מתחום ה-א"ב חוזרים ציקלית לסוף.

38 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©38 תרגיל 8, סעיף ב' ידוע כי יוליוס קיסר נהג להשתמש רבות במילה "technion". אנו יכולים לנצל עובדה זו כדי לפענח את הודעותיו של יוליוס קיסר גם ללא ידיעת המפתח. כתוב פונקציה:int fullDecrypt (char *Edata) –אשר מגלה את המפתח ומחזירה אותו. –אם הפונקציה לא הצליחה עליה להחזיר 1-. –אסור לשנות את מחרוזת הפרמטר. –שימו לב שבסעיף זה פרמטר Edata הינו מחרוזת, כלומר מסתיים ב-‘\0’. הדרכה: –נניח שבהודעה המקורית מופיעה המילה "technion" ונחפש את המפתח שעבורו יתגלה רצף זה. –אם מצאנו מפתח כזה אז נחליט שזה המפתח המקורי שיוליוס קיסר השתמש בו. –אם לא, אז נחפש מפתח אחר. הערה: תיאורטית יתכן כי נמצא מפתח שאינו נכון אבל עבורו הרצף המבוקש ("technion") אכן יתגלה. הנח כי במקרה כזה עדיין הפענוח חוקי.

39 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©39 הדרך לפתרון – אפשרות א כדי לגלות את המפתח חייבים לנסות את כל המפתחות האפשריים אחד-אחד. אבל אנחנו לא יכולים להפעיל decrypt על Edata כי אנחנו לא יכולים לעשות מערך עזר בגודל המתאים וגם אסור לשנות את Edata. אבל אנחנו יכולים לעשות מערך עזר בגודל 8 (strlen(“technion”)=). לכן אפשר לממש אלגוריתם הבא: –נעבור על כל תתי המחרוזות של Edata בגודל 8. –נפענח כל תת מחרוזת עם כל 26 המפתחות האפשריים. –אם קיבלנו "technion", מצאנו את המפתח.

40 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©40 פתרון 8 סעיף ב' – פונקציות עזר int strlen(char *string) { int len = 0; while(string[len] != '\0') { len++; } return len; } int strcmp_len(char *str1, char *str2, int len) { int i; for (i = 0; i < len; i++){ if (str1[i] != str2[i]){ return (str1[i] - str2[i]); } return 0; }

41 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©41 פתרון 8 סעיף ב' – אפשרות א #define TECH_LEN 8 /* 8 is the length of the word technion */ int fullDecrypt(char *Edata) { int n,i; char check[TECH_LEN]; if (strlen(Edata) < TECH_LEN) { return -1; } for (n=0; n < LETTERS_NUM; n++) { for (i=0; Edata[i + TECH_LEN - 1] != '\0'; i++) { decrypt(Edata+i, TECH_LEN, n, check); if (strcmp_len(check, "technion", TECH_LEN) == 0) { return n; } } } return -1; } בודקים את כל המפתחות על כל תתי המחרוזות בגודל 8 מפענחים, ואם קבלנו “technion” מצאנו n מתאים.

42 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©42 הדרך לפתרון – אפשרות ב לשים לב ש: –אם Edata מכיל תת מחרוזת “technion” אז המפתח הוא n=0. –אם הצפין את המחרוזת “technion” עם n=1 נקבל “ufdiojpo”. –לכן אם Edata מכיל תת מחרוזת “ufdiojpo” אז המפתח הוא n=1. לכן אפשר לממש אלגוריתם הבא: –נצפין מחרוזת “technion” עם אחד מ-26 המפתחות האפשריים. –אם תוצאת ההצפנה היא תת מחרוזת של Edata, מצאנו את המפתח. הבחנה נוספת: אין לנו פונקציה שמצפינה מחרוזת (encrypt). אבל נשים לב שפענוח עם n=1 שקול להצפנה עם n=25, פענוח עם n=2 שקול להצפנה עם n=24 וכו'. לכן במקום לכתוב פונקציה encrypt אפשר להשתמש בפונקציה decrypt.

43 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©43 פונקציות עזר נשתמש בפונקציות עזר מפתרון הקודם. בנוסף נממש פונקציה strstr(char *s1, char *s2) שמחזירה 1 אם s2 היא תת מחרוזת של s1 ו-0 אחרת. int strstr(char *s1, char* s2) { int len1 = strlen(s1), len2 = strlen(s2); int i; for (i = 0; i <= len1-len2; i++) { if (strcmp_len(s1+i, s2, len2) == 0) { return 1; } return 0; }

44 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©44 פתרון 8 סעיף ב' – אפשרות ב #define TECH_LEN 8 /* 8 is the length of the word technion */ int fullDecrypt(char *Edata) { int n,i; char technion[] = “technion”; if (strlen(Edata) < TECH_LEN) { return -1; } if (strstr(Edata, technion)) { return 0; } for (n = 1; n < LETTERS_NUM; n++) { decrypt(technion, TECH_LEN, 1, technion); if (strstr(Edata, technion)) { return LETTERS_NUM-n; } } return -1; } בודקים את כל המפתחות חוץ מ-0 מוספים עוד 1 לפענוח תרגום של מפתח הפענוח למפתח ההצפניה.


Download ppt "שאלות ממבחנים. 14 תרגולמבוא למדעי המחשב. כל הזכויות שמורות ©2 תרגיל 1: מטריצות כתבו פונקציהvoid Rotation(int in [N][N], int out [N][N]) אשר מקבלת שני."

Similar presentations


Ads by Google