אוניברסיטת חיפה החוג למדעי המחשב מרצה: שולי וינטנר מתרגלים: נעמה טוויטו, מחמוד שריף מבוא למדעי המחשב סמסטר א' תשע"ב בחינת סיום, מועד א', 6.2.2012 הנחיות: 1. משך הבחינה: 120 דקות. 2. היציאה מהכיתה במהלך הבחינה אסורה. 3. אין להשתמש בכל חומר עזר. 4. ודאו כי בטופס שבידיכם 10 עמודים. עליכם לכתוב את התשובות על הטופס ולהגיש את כל הטופס ואת הטופס בלבד. 5. קראו היטב כל שאלה וודאו שאתם מבינים אותה לפני שתתחילו לענות עליה. אם יש שאלות, פנו למרצה או למתרגלים. 6. כתבו בכתב יד ברור וקריא. ניתן לכתוב בעיפרון. 7. ניתן לכתוב הערות בעברית, גם בגוף פונקציות C. 8. אם לא נכתב אחרת, כאשר אתם מתבקשים להגדיר פונקציה, עליכם להגדיר פונקציה אחת בדיוק. אין להגדיר או להשתמש בפונקציות נוספות. 9. אם לא נכתב אחרת, מותר להשתמש בפונקציות וקבועים שנלמדו בכיתה מתוך הספריות stdio ו- stdlib בלבד.לא ניתן להשתמש בפונקציות שלא נלמדו בכיתה. 10. אם מוגדרות דרישות סיבוכיות, על הפתרון שלכם לעמוד בהן. פתרון שלא יעמוד בדרישות הסיבוכיות לא יזכה בנקודות כלל. בהצלחה! שאלה 1 2 3 ציון /30 /30 /40 סה"כ 1
שאלה (30%) 1 double Mystery1(double x, int n) int i; double temp=1.; for(i=1;i<=n;i++) temp *= Mystery2(x,i); temp *= temp; for(i=0;i<n;i++) temp /= Mystery2(x,n); return temp; נתונה הגדרה של שתי פונקציות: double Mystery2(double x, int n) if(n==0) return 1; else return x*mystery2(x,n-1); א. (10%) הסבירו בקצרה ובדייקנות מה מחשבת Mystery1(x,n) כפונקציה של x ו- n. הניחו ש- n אינו שלילי. שימו לב שטעות בסעיף זה תשרה טעות נגררת בשאר הבעיה: עליכם לדייק כאן! התכנית מחשבת ומחזירה את x n ב. (5%) מהי הסיבוכיות (הכוללת) של,Mystery1 כפונקציה של n? O(n 2 ) 2
ג. (15%) הגדירו פונקציה שקולה ל- Mystery1 שהסיבוכיות שלה (n.o(log לא ניתן להשתמש בפונקציות חיצוניות ולא ניתן להגדיר יותר מפונקציה אחת בבעיה זו. אם אינכם מוצאים פתרון, הגדירו פונקציה בסיבוכיות,O(n) עבור 5 נקודות. double f(double x, int n) double temp; if(n==0) return 1; temp = f(x,n/2); if(n%2 == 0) return temp*temp; return x*temp*temp; 3
שאלה (30%) 2 נתונה ההגדרה הבאה של צמתים בעץ בינארי: typedef struct tnode *Tnodep; typedef struct tnode int contents; /* contents of the node */ Tnodep left, right; /* left and right children */ Tnode; הגדירו פונקציה שחתימתה: int same (Tnodep root1, Tnodep root2); הפונקציה מקבלת שני מצביעים לעצים בינאריים, ומחזירה 1 אם העצים זהים, 0 אחרת. שני עצים הם זהים אם המבנה שלהם זהה, ואם תוכן הצמתים באותו מקום במבנה זהה אף הוא. למשל, העצים הבאים אינם זהים, אבל תתי העצים של שניהם, שהשורש שלהם הוא 2, זהים: 7 7 / \ / \ 3 2 3 2 / / \ / / \ 5 1 3 9 1 3 6 6 הבהרות: בעץ בינארי לכל צומת לכל היותר שני בנים (אך אולי פחות). 1. אסור לפונקציה להרוס את מבני העצים שהיא מקבלת כקלט. 2. לא ניתן להשתמש בפונקציה במשתנים חיצוניים או סטטיים. 3. לא ניתן להגדיר יותר מפונקציה אחת. 4. 4
int same(tnodep r1, Tnodep r2) if (r1==null && r2==null) return 1; else if (r1==null && r2!=null) return 0; else if (r1!=null && r2==null) return 0; else return (r1->contents==r2->contents && same(r1->left,r2->left) && same(r1->right,r2->right)); 5
שאלה (40%) 3 מערך בגודל n של שלמים הוא דליל אם לכל היותר SIZE מהתאים בו מכילים ערכים שאינם 0. בשאלה זו הניחו ש- SIZE הוא קבוע, למשל 100. כרגיל, נניח ש- n גדול, ובפרט גדול בהרבה מ- SIZE. בשאלה זו עליכם למצוא ייצוג חסכוני בזיכרון עבור מערך דליל. 1 0 2 0 3 0 4 0 0 0 5 0 0 0 0 1 2 3 4 0 0 0 0 0 0 0 0 1 0 0 0 לדוגמה, אם SIZE=5 אזי המערכים הבאים דלילים: 1 n 1.(5%) הגדירו פונקציה המקבלת מערך של שלמים a דליל, 0 אחרת. ואת גודלו ומחזירה אם המערך int is_sparse(int a[], int n) int i,count=0; for (i=0; i<n; i++) if (a[i]) count++; return (count<=size); 6
2. (10%) הציעו מבנה נתונים חסכוני במקום כדי לאחסן בו את האברים של מערך דליל. הפיתרון צריך לאפשר המרה של מערך דליל למבנה שהצעתם ובחזרה בסיבוכיות.O(n) כמו כן, הזיכרון הנדרש כדי לאחסן מערך דליל בגודל n צריך להיות ליניארי ב- SIZE, ולא תלוי ב-.n תארו במילים את המבנה המוצע: רשומה ובה שני שדות: השדה storage הוא מערך בגודל SIZE של זוגות, שכל אחד מהם מורכב משני שלמים: index המציין אינדקס של תא במערך המקורי שבו מספר שאינו אפס; ו- value השומר את ערך האבר באותו האינדקס. השדה השני ברשומה,,size מכיל את גודלו של המערך המקורי. הגדירו טיפוס נתונים בשם SparseArray המממש את הפתרון המוצע: typedef struct int size; struct int index; int value; storage[size]; SparseArray; 7
3. (10%) הגדירו פונקציה הממירה מערך דליל למבנה הנתונים שהצעתם. הפונקציה מקבלת מערך דליל a ואת אורכו n וכן מצביע s למבנה מטיפוס,SparseArray ומחזירה מספר שלם, שהוא גודל המבנה s. כמובן, על הפונקציה לייצג את המערך a במבנה s. int array_to_sparse (int a[], int n, SparseArray *s); 4. (10%) הגדירו פונקציה הממירה את מבנה הנתונים שהצעתם למערך רגיל. הפונקציה מקבלת מצביע s למבנה שהצעתם, ומספר שלם המציין את גודל המבנה. כמו כן היא מקבלת כתובת של מערך שבו יש לאחסן את נתוני המבנה. היא מחזירה מספר שלם המציין את גודל המערך. int sparse_to_array (SparseArray *s, int k, int a[]); על כל אחת משתי הפונקציות לעבוד בסיבוכיות.O(n) כמו כן, אם a הוא מערך בגודל n אזי ביצוע שתי ההוראות הבאות: k = array_to_sparse(a,n,&s); n = sparse_to_array(&s,k,a); לא ישנה כלל את התוכן של a ואת הערך של n. 8
int array_to_sparse (int a[], int n, SparseArray *s) int i,j=0; for (i=0; i<n; i++) while (i<n && 0==a[i]) i++; if (i<n) (s->storage)[j].index = i; (s->storage)[j].value = a[i]; j++; s->size = n; return j; 9
int sparse_to_array (SparseArray *s, int len, int a[]) int i,j=0; for (i=0; i < len; i++) while (j<(s->storage)[i].index) a[j]=0; j++; a[j]=(s->storage)[i].value; j++; while (j<s->size) a[j]=0; j++; return j; 10