החוג למדעי המחשב אוניברסיטת חיפה מבוא למדעי המחשב סמסטר א' תשע"ג בחינת סיום, מועד ב', 20.02.2013 מרצה: ריטה אוסדצ'י מתרגלת: נעמה טוויטו מדריך מעבדה: מחמוד שריף משך המבחן: שעתיים חומר עזר: ספר של Kernighan & Ritchie הנחיות: עליכם לכתוב את התשובות על הטופס ולהגיש את כל הטופס. 1. היציאה מהכיתה במהלך הבחינה אסורה. 2. קראו היטב כל שאלה וודאו שאתם מבינים אותה לפני שתתחילו לענות עליה. 3. אם יש שאלות, פנו למרצה או למתרגלים. כתבו בכתב יד ברור וקריא. ניתן לכתוב בעיפרון. 4. ניתן לכתוב הערות בעברית, גם בגוף פונקציות C. 5. ניתן להשתמש בכול פונקציה שלמדנו בהרצאות בתוספת הצהרה והערה על 6. מטרתה. פתרונות פתרונות צריכים להיות יעילים ככל האפשר. פתרונות לא יעילים ו 7. שלא עונים על דרישות הסיבוכיות יקבלו ניקוד חלקי. אם לא נכתב אחרת, ניתן להשתמש בפונקציות עזר. 8. בהצלחה!!! שאלה 1 2 3 סה"כ ציון /30 35/ /35 100
שאלה )30 1 נק'( נתונה התכנית הבאה )n הוא מס' שלם וחיובי(: #include <stdio.h> #include <stdlib.h> int func1(int n); int func2(char* a, int i, int n); int func1(int n) char* a = (char*)malloc((n+1)*sizeof(char)); int tmp; if(a==null) exit(1); a[n] = 0; tmp = func2(a,0,n); free(a); return tmp; int func2(char* a, int i, int n) int x = 0; if(i == n) printf("%s\n",a); return 1; a[i] = '1'; x += func2(a,i+1,n); if(i==0 a[i-1]!='0') a[i] = '0'; x += func2(a,i+1,n); return x; int main() printf("%d\n",func1(7)); return 0;
n )כאן א. הסבירו במילים פשוטות מה התכנית מבצעת: התכנית מדפיסה את כל המחרוזות הבינאריות מאורך רצופים, ולבסוף מדפיסה את מספרן. 7=n( שאין בהן שני אפסים ב. מהי סיבוכיות הזמן של ההדוק ביותר. func1 כפונקציה של n? סמנו ב- x את הריבוע שליד החסם העליון O n O n 2 O 2 n O(n!) X ג. מהי סיבוכיות המקום של func1 ו- func2 כפונקציה של n? וקוראת ל- func2 (. O(n) זיכרון בגודל )מקצה O(n) :func1. n( רקורסיבית שמגיעה עד לעומק )פונק' O(n) : func2
שאלה )35 2 נק'( נתונה ההגדרה הבאה של איבר ברשימה מקושרת: typedef struct list int data; struct list* next; List; הגדירו פונקציה שחתימתה: List* setdiff(list* list1, List* list2); הפונקציה מקבלת שתי רשימות מקושרות ממוינות בסדר עולה ומוחקת מהרשימה הראשונה (list1) את האיברים שמופעים ברשימה השנייה (list2). הפונקציה מחזירה את הרשימה המעודכנת. לדוגמא: list1: 1 2 5 6 9 11 15 NULL list2: 2 4 5 6 15 NULL אחרי העדכון : list1=setdiff(list1,list2) list1: 1 9 11 NULL אין לעבור על הרשימות יותר מפעם אחד. יש לממש פונקציה אחת בלבד ללא שימוש בפונקציות עזר פרט לפונקציות מספריה של C. על הפונקציה לעמוד בדרישות סיבוכיות מקום של (1)O.
אלגוריתם : עוברים על שתי הרשימות בו זמנית עד שמגיעים לסופה של אחת מהרשימות בצורה הבאה: מאתחלים שני מצביעים לתחילתן של שתי הרשימות. בכל שלב מקדמים את המצביע שמצביע על הרשומה בעלת הערך היותר קטן, ואם באיזשהו שלב שני המצביעים מצביעים לרשומות בעלות ערכים זהים אז מוציאים את הרשומה שנמצאת ברשימה הראשונה ומשחררים את הזיכרון שהיא תופסת. סיבוכיות הזמן: O(n) O(1) סיבוכיות המקום:
typedef struct list int data; struct list* next; Node; מימוש ב- C : Node* setdiff(node* list1, Node* b) Node* tmp=list1; Node* a=list1; while (a!=null && b!=null) if (a->data == b->data) if(a==list1) /* first element is removed*/ a=a->next; free(list1); list1=a; tmp=a; b=b->next; else /* remove element other than first*/ b = b->next; tmp->next=a->next; free(a); a=tmp->next; else if (a->data < b->data) /*advance the list with the smaller element*/ tmp=a; a = a->next; else b = b->next; return list1;
שאלה )35 3 נק'( נתונה ההגדרה הבאה של צמתים בעץ בינארי: typedef struct tnode *Tnodep; typedef struct tnode int content; /* content of the node */ Tnodep left,right; /* left and right children */ Tnode; int scantree(tnodep root1,tnodep root2, int d); הגדירו פונקציה שחתימתה: הפונקציה מקבלת מצביעים לשני עצים, ושלם d. יש להניח שהעצים הם מסוג עץ חיפוש בינארי מאוזן ומלא בעל n צמתים. הפונקציה תחזיר 1 אם קיימים קודקוד עם ערך x בעץ הראשון )root1( וקודקוד עם ערך y בעץ השני )root2( כך שמתקיים ש,x=y-d אחרת הפונקציה תחזיר 0. לדוגמא: עבור העצים root1 ו- root2 שבציור הבא עבור 3=d הפונקציה תחזיר 1, כי התנאי מתקיים, למשל, עבור = 5 x ו -8 = y עבור 20=d הפונקציה תחזיר 0, כי התנאים לא מתקיימים עבור אף זוג קודקודים. root2 5 root1 6 3 7 3 8 2 4 6 8 1 5 7 9 להזכירכם: עץ חיפוש בינארי הוא עץ ממויין כך שלכל קודקוד בעץ מתקיים: כל הצאצאים בתת העץ של הבן הימני הם בעלי ערך גדול יותר מערך הקודקוד וכל הצאצאים בתת העץ של הבן השמאלי הם בעלי ערך קטן יותר. על הפונקציה לעמוד בדרישות סיבוכיות זמן של.O(nlogn) הבהרות: לא ניתן להשתמש במשתנים חיצוניים או סטטיים. אסור לפונקציה להרוס את העצים שהיא מקבלת כקלט..1.2
אלגוריתם : עבור כל צומת x בעץ הראשון נחפש את x+d בעץ השני, אם הוא נמצא נחזיר 1, אחרת נבדוק את בניו של x. הסבר סיבוכיות הזמן: O(nlogn) כי עבור כל צומת בעץ הראשון, ויש n כאלה, מבוצעת פעולת חיפוש אחת בעץ השני )סיבוכיות הזמן של פעולת חיפוש בעץ בינארי מאוזן בן n צמתים היא O(logn) (.
int binary_search(tnodep root, int val) if(root==null) return 0; if(root->content==val) return 1; if(root->content>val) return binary_search(root->left,val); return binary_search(root->right,val); מימוש ב- C : int scan(tnodep root1,tnodep root2, int d) if(root1==null) return 0; if(binary_search(root2,root1->content+d)) return 1; return scan(root1->left,root2,d) scan(root1->right,root2,d);