חוברת תרגול
חוברת תרגול
חוברת תרגילים
-1-
קלט פלט
שאלה 1
א .כתבו תוכנית המדפיסה לוח כפל בגודל . 10 ×10
ב .כתבו תוכנית המקבלת מספר ,MaxMult ,ומדפיסה לוח כפל בגודל . MaxMult × MaxMult
שאלה 2
כתבו את הפונקציה:
)void printFormattedIntegers(char* format, char* numbers
הפונקציה מקבלת כקלט מחרוזת ,format ,המכילה פורמט להדפסה של מספרים וכן מחרוזת,
,numbersהמכילה מספרים שלמים בבסיס דצימלי מופרדים במספר כלשהו של רווחים לבנים.
על הפונקציה להדפיס את המספרים מהמחרוזת ,numbersבהתאם לתווי ההסבה שב .format-כך
שתו ההסבה הראשון ב format-יקבע כיצד ייוצג המספר הראשון ב ,numbers-תו ההסבה השני
יקבע כיצד ייוצג המספר השני וכך הלאה )בדומה ל.(printf-
מחרוזת הפורמט יכולה להכיל את תווי ההסבה הבאים )כמו ב:(printf -
– %dממיר intלטקסט המכיל ייצוג עשרוני של המספר
– %xממיר intלטקסט המכיל ייצוג הקסהדצימלי )בסיס (16של המספר
– %oממיר intלטקסט המכיל ייצוג אוקטלי )בסיס (8של המספר
וכן מחרוזת הפורמט יכולה להכיל את תווי ההסבה הבאים אשר אינם חוקיים ב:printf -
– %bממיר intלטקסט המכיל ייצוג בינארי )בסיס (2של המספר
– %rממיר intלטקסט המכיל ייצוג רומי של המספר
כמו כן מחרוזת הפורמט יכולה להכיל תווים שאינם תווי הסבה ,אשר מודפסים כמו שהם.
-2-
דוגמאות:
הקריאה:
printFormattedIntegers("Dec: %d Hex: %x Roman: %r"," 123 10
)"9
תגרום להדפסת הפלט:
Dec: 123 Hex: A Roman: IX
הקריאה:
)"printFormattedIntegers("%b in Binary is %o in Octal" ,"18 18
תגרום להדפסת הפלט:
10010 in Binary is 22 in Octal
הנחיות:
היעזרו בוויקיפדיה כדי למצוא את התיאור המלא של שיטת הספירה הרומית: .1
[Link] את הערך":ספרות רומיות"
הניחו כי הקלט לפונקציה תקין ,כלומר הניחו כי המחרוזת numbersאכן מכילה מספרים .2
שלמים מיוצגים בבסיס 10ומופרדים ברווח לבן וכי formatמכיל מחרוזת פורמט חוקית וכן
שמספר תווי ההסבה במחרוזת הפורמט מתאים למספר המספרים שהתקבלו במחרוזת
.numbers
השתמשו ככל הניתן בפונקציות הקלט/פלט שנלמדו בשיעור printf ,scanf ,sscanf ,sprintf .3
וכו'.
ניתן להיעזר בפונקציה ) strtokחפשו תיעוד המסביר כיצד להשתמש בה( אך בהחלט ניתן .4
להסתדר גם בלעדיה.
הגדירו פונקציות עזר וחלקו את הבעיה לתת בעיות. .5
-3-
מצביעים והקצאות דינאמיות
שאלה 1
כתבו את הפונקציה: א.
;)int** pointerSort(int* arr, int size
הפונקציה מקבלת כקלט מערך של מספרים שלמים ,arr ,ואת גודלו.size ,
על הפונקציה להחזיר מערך של מצביעים ,כך שהמצביעים במערך יצביעו על איברי arr
בצורה ממוינת מהקטן לגדול.
כלומר ,המצביע בתא ה 0-של המערך המוחזר מצביע לאיבר המינימלי.
שאלה 2
בהינתן פולינום עם מקדמים שלמים מהצורה:
Cn X n + Cn −1 X n −1 + ... + C1 X 1 + C0
כל איבר בפולינום נקרא מונום .נגדיר רשומה לייצוג מונום כנ"ל באופן הבא:
{typedef struct monom
;int coefficient המקדם//
;int power החזקה//
;}Monom
מבנה הנתונים לייצוג פולינומים :מערך של רשומות מטיפוס ,Monomהמקיים:
• המערך לא יכיל מונום שמקדמו .0
• המונומים במערך יופיעו בסדר חזקות יורד ממש )כלומר המונום עם החזקה הגדולה ביותר יופיע
בתא הראשון במערך(.
כתבו תוכנית הקולטת מהמשתמש שני פולינומים ,ומדפיסה את פולינום הסכום שלהם ואת פולינום
המכפלה שלהם ,כל אחד בשורה נפרדת.
הערות:
.1כל פולינום בקלט יהיה שורה באורך לא ידוע של זוגות )מקדם וחזקה(.
כך למשל השורה:
2 4 -5 1 0 6 6 4 -8 0 7 3
מייצגת את הפולינום. 8 x 4 + 7 x 3 − 5 x − 8 :
.2הדפסת פולינום צריכה להיות בסדר חזקות יורד ,ללא מקדמים שהם .0
למשל את הפולינום 8 x 4 + 7 x 3 − 5 x − 8 :יש להדפיס.8x^4 + 7x^3 - 5x - 8 :
-4-
שאלה 3
כתוב תוכנית הקולטת שורות טקסט מהמשתמש ואוגרת אותן במערך של מחרוזות.
התוכנית תקלוט בהתחלה מספר הקובע את גודל המאגר ,ולאחר מכן תקלוט שורות אותן תכניס למאגר.
במידה והמאגר מתמלא ,יש "לזרוק" את השורה הותיקה ביותר.
בנוסף לתחזוקה של מבנה הנתונים המתואר לעיל ,על התוכנית לאפשר למשתמש לשחזר שורות מתוך
המאגר .פקודות השחזור ניתנות כאן:
משחזרת את השורה האחרונה שהוכנסה למאגר. !!
משחזרת את שורה מספר .nבמידה ואין כזו -תודפס הודעת שגיאה. !n
)מספרי השורות ניתנים באופן רציף מתחילת התוכנית ועד סיומה(
משחזרת את השורה האחרונה שהתחילה ב str -מהמאגר .במידה ואין !str
כזו ,תודפס הודעת שגיאה.
מדפיסה את תוכן המאגר .כל שורה תופיע אחרי מספר השורה. !print
)מספרי השורות ניתנים באופן רציף מתחילת התוכנית ועד סיומה(
יציאה. !quit
-5-
שאלה 4
כתוב פונקציה המקבלת שני פרמטרים שהם שתי מחרוזות.
הפונקציה מוציאה מן המחרוזת הראשונה את כל התווים המופיעים במחרוזת השנייה.
הפונקציה מחזירה מחרוזת חדשה המכילה את הרצף המכווץ.
לדוגמא:
)” strsqz ("hello world", “lתוציא "“heo word
אם הפונקציה הופעלה בשנית ,עם פרמטר ראשון שהוא המחרוזת הריקה )"" או ,(NULLיש לבצע את
הכיווץ על תוצאת ההפעלה הקודמת של הפונקציה.
לדוגמא:
)" strsqz (NULL, "orתוציא ".“he wd
-6-
רשימות מקושרות
שאלה 1
נתונים המבנים הבאים לייצוג רשימה מקושרת של תווים:
typedef struct list_node
{
;char* dataPtr
;struct list_node* next
;}ListNode
נתונה רשימה מקושרת שנתוניה הם ספרות ,ואותיות אנגליות קטנות בלבד .הרשימה המקושרת
במקורה הכילה את המידע הבא על תלמיד :שמו הפרטי של התלמיד )המופיע באותיות קטנות( אות אחר
אות ברשימה ,ואחריו מופיע ציונו הממוצע )הניתן בספרות המייצגות מספר חיובי שלם( סיפרה אחר
סיפרה ברשימה .לרוע המזל ,כתוצאה מבאג במחשב ,נשזרו התווים אלו באלו ,והתקבלה רשימה
מעורבלת.
דוגמה :רשימה שבמקור הכילה את התווים muℓℓy94כאשר mהיה הנתון בצומת הראשון u ,היה
הנתון בצומת השני ,וכ"ו )כלומר שמו הפרטי הוא ,muℓℓyוציונו ,(94שונתה וכעת היא מכילה את
התווים) m9uℓ4ℓy :כאשר mהוא הנתון בצומת הראשון 9 ,הוא הנתון בצומת השני ,וכ"ו(.
שימו לב כי סדר התווים והספרות המקורי נשמר בתוך הערבול) .לדוגמא u ,יבוא אחרי ℓ ,mיבוא אחרי
,uוכו'(.
כתבו פונקציה המקבלת רשימה מעורבלת ומחזירה מבנה לייצוג תלמיד )שיוגדר להלן( המכיל את שמו
הפרטי ואת ציונו הממוצע של התלמיד המתקבלים מהפרדת המילים ברשימה המעורבלת.
הערות:
• אין להשתמש בהקצאה דינאמית ,אלא לשנות מצביעים ברשימת הקלט.
-7-
שאלה 2
נתונה ההגדרה הבאה לייצוג רשימה מקושרת של מספרים שלמים:
{typedef struct listNode
;int* dataPtr
;struct listNode* next
;}ListNode
הפונקציה מקבלת כקלט lst1ו ,lst2-שתי רשימות מקושרות ממוינות בסדר עולה של ערכים
עליהם מצביעים השדות .dataPtr
על הפונקציה למזג את שתי הרשימות לרשימה ממוינת אחת המכילה את כל האיברים של רשימות הקלט.
על הפונקציה להחזיר את הרשימה הממוזגת.
בגרסא זו ,הפונקציה איננה רקורסיבית ועליה ליצור רשימה חדשה. א.
הפונקציה לא תשנה הצבעות ברשימות lst1ו) lst2 -בסוף ריצת הפונקציה שתי הרשימות
נותרות ללא שינוי(.
בגרסא זו ,הפונקציה איננה רקורסיבית ועליה למזג את שתי הרשימות לרשימה אחת ממוינת ע"י ב.
שינוי מצביעים בלבד )ללא שימוש בהקצאות חדשות(.
בגרסא זו ,הפונקציה רקורסיבית ועליה למזג את שתי הרשימות ע"י שינוי מצביעים. ד.
הערה :בסעיפים ג' ו -ד' הפונקציה אינה חייבת להיות רקורסיבית בעצמה ,היא יכולה להיות פונקציה
העוטפת פונקציה רקורסיבית )פונקציה אשר מפעילה לפונקציה רקורסיבית(.
-8-
שאלה 3
נתונה ההגדרה הבאה לייצוג רשימה מקושרת של מספרים שלמים:
{typedef struct listNode
;int* dataPtr
;struct listNode* next
;} ListNode
ניתן לייצג מספר טבעי גדול בעזרת רשימה של ספרותיו לפי הסדר כאשר הצומת הראשון ברשימה מכיל
מצביע לספרה הימנית והצומת האחרון מכיל מצביע לספרה השמאלית.
למשל את המספר 197נייצג ברשימה:
;)void addNumbers(List n1, List n2, List* sum ב .כתבו את הפונקציה:
שמקבלת 2רשימות שמייצגות שני מספרים ומצביע לרשימה שלישית ומעדכנת את sumלהצביע על
רשימה השלישית המייצגת את סכום 2המספרים.
הערה :בסעיפים ב' ו -ג' אין להשתמש באלגוריתם הממיר את המספרים המיוצגים ברשימות למשתנים
מטיפוס intאו doubleולבצע את החיבור והכפל עליהם )גישה כזו מחמיצה את המטרה של ייצוג
המספרים ברשימה(.
-9-
שאלה 4
נתון המבנה הבא לייצוג רשימה מקושרת דו-כוונית:
{typedef struct dListNode
;int* dataPtr
;struct dListNode* next
;struct dListNode* prev
;}DListNode
כתבו את הפונקציה:
;)void removeDuplicates(DList* lst
הפונקציה מקבלת מצביע לרשימה דו-כוונית של ציוני מבחן פסיכומטרי ,בה כל צומת מכיל מצביע לציון
של מבחן )כל ציון הינו מספר שלם בין 200ל .(800 -כל ציון יכול להופיע יותר מפעם אחת .על
הפונקציה לשנות את הרשימה המקורית כך שכל ציון יופיע בה פעם אחת בלבד .על הפונקציה לעדכן את
lstלהכיל את הרשימה המצומצמת ולשחרר את הזיכרון של הצמתים שהוסרו.
- 10 -
שאלה 5
נתונות ההגדרות הבאות:
{typedef struct letterEncrypt
;char letter
;int count
;}LetterEncrypt
- 11 -
עצים בינאריים
שאלה 1
עץ בינארי מוגדר כך:
{typedef struct treeNode
;int data
;struct treeNode* left
;struct treeNode* right
;} TreeNode
כתבו את פונקציה:
;)float averageOfValues(Tree tr
3
2 5
7 9
1
- 12 -
שאלה 2
בהינתן ההגדרה הבאה למבנה עבור עץ בינארי:
{ typedef struct treeNode
;int data
;struct treeNode* left
;struct treeNode* right
;}TreeNode
אם Tהוא עץ בינארי נגדיר כי " Tמאוזן עפ"י גובה" כאשר לכל צומת ,גובה תת העץ השמאלי וגובה
תת העץ הימני שווים או שהפרשם לא גדול מ .1 -
3
9 6
1 1
הערות:
.1אין להשתמש במשתנים סטטיים.
.2גובה של עץ עם צומת יחיד מוגדר להיות .0
.3עץ ריק הוא מאוזן לפי גובה.
- 13 -
שאלה 3
נתונים המבנים הבאים עבור עץ בינארי ועבור רשימה מקושרת:
3
2 5
1
- 14 -
שאלה 4
קוטר של עץ בינארי מוגדר להיות מספר הקשתות במסלול הארוך ביותר בין כל שני צמתים בעץ.
למשל ,בעץ הנ"ל המסלול המודגש הוא המסלול הארוך ביותר בין שני צמתים בעץ ,ולכן קוטר העץ הנ"ל
הוא .6
כתבו את פונקציה:
;)int treeDiameter(Tree tr
- 15 -
שאלה 5
עץ בינארי מוגדר כך:
{typedef struct treeNode
;int data
;struct treeNode* left
;struct treeNode* right
;} TreeNode
כתבו את פונקציה:
;)void printByLevels(Tree tr
המדפיסה את הנתונים בעץ trלפי רמות )קודם את הנתון ברמה ,0אחריו את נתונים ברמה ,1אחריהם
את הנתונים ברמה ,2וכך הלאה( ,כל רמה תודפס משמאל לימין.
על הפונקציה לרוץ ביעילות ) , Θ(nכאשר nהוא מספר הצמתים הכולל בעץ.
3
2 5
1
יודפס3 2 5 4 7 9 1 :
הערות:
.1בכדי לעמוד בדרישות היעילות ייתכן ותרצו להשתמש במבנה נתונים נוסף.
.2אין להשתמש במשתנים סטאטיים.
- 16 -
קבצים
שאלה :1
כתבו תוכנית המקבלת כפרמטר שם של קובץ טקסט .הקובץ מכיל אינפורמאציה על מלאי של מוצרים
בחנות.
בשורה הראשונה יופיע מספר המייצג את מספר המוצרים במאגר.
בכל שורה החל מהשורה השנייה יופיעו הנתונים על מוצר אחד .עבור כל מוצר במאגר יישמרו )משמאל
לימין בשורה( :שם המוצר ,מחיר של יחידה אחת ,מספר היחידות הזמינות.
בין כל שדה בשורה יכולים להופיע מספר כלשהו של סימני .tab
שימו לב :שם של מוצר יכול להיות יותר ממילה אחת.
4
iPod nano 1000 12
iRiver 1199 4
Sony play station 3 3499 30
Xbox 1819 5
על התוכנית להמיר קובץ זה לקובץ בינארי הבנוי לפי הפורמט הבא:
• מספר מטיפוס – intהמייצג את מספר המוצרים השונים במאגר
• עבור כל מוצר במאגר )שורה בקובץ הטקסט( ישמרו בקובץ הבינארי המיוצר ,הנתונים
הבאים:
.1מספר מטיפוס – intהמייצג את מספר התווים בשם המוצר )ללא ה.('\0' -
.2רצף )באורך זה( של -charים – המכיל את שם המוצר.
.3מספר מטיפוס – intהמייצג את מחירו של המוצר.
.4מספר מטיפוס – intהמייצג את מספר היחידות הזמינות מהמוצר.
שמו של הקובץ המיוצר הוא כשמו של קובץ הקלט ,בתוספת " ".binבסוף.
למשל :נניח ששם קובץ הקלט הוא " "[Link]שם הקובץ שיווצר יהיה "."[Link]
- 17 -
שאלה 2
א .בסעיף זה נרצה להמיר תמונה צבעונית לתמונה בגווני אפור.
תמונה צבעונית מורכבת מפיקסלים )נקודות( בצבעים שונים .מספר הפיקסלים בתמונה )רזולוציה( הוא
רוחב התמונה כפול גובה התמונה.
כל פיקסל בתמונה מיוצג על ידי שלשת מספרים ) (R,G,Bהקובעת את עוצמת האדום ,הירוק והכחול
בהתאמה.
הערכים השונים אותם יכולים לקבל ,G,Rו B-נקבעים בהתאם לעומק התמונה .depth ,בתמונה בעומק
xכל אחד מבין ,G,Rו B-יכול לקבל ערך בין 0ל) x-וכך מספר הגוונים האפשריים בתמונה הוא .( x 3
לדוגמא בתמונה צבעונית בעומק 255כל אחד מבין R,G,Bהוא מספר בין 0ל 255-כאשר 0מציין כי
הגוון אינו מופיע כלל ,ו 255-מציין כי הגוון מופיע במלואו .כל ערך בין 0ל 255-קובע עוצמה עבור
הגוון.
השלשה ) (255,0,0תציין את הצבע אדום )אדום מופיע במלואו ,ירוק וכחול אינם מופיעים כלל(
השלשה ) (0,255,0תציין את הצבע ירוק )אדום וכחול אינם מופיעים כלל ,ירוק מופיע במלואו(
השלשה ) (255,0,255תציין את הצבע סגול )אדום וכחול מופיעים במלואם ,ירוק אינו מופיע כלל(
השלשה ) (255,255,255תציין את הצבע לבן )כל הצבעים מופיעים במלואם(
השלשה ) (0,0,0תציין את הצבע שחור )כל הצבעים אינם מופיעים כלל(
השלשה ) (230,160,15תציין גוון של הצבע כתום )בהתאם ליחס בין מרכיבי הצבע השונים(
תמונה בגווני אפור מורכבת מפיקסלים בגווני אפור שונים .אלא שהפעם כל פיקסל בתמונה מיוצג על ידי
מספר בודד המציין את רמת האפור של הפיקסל .גם כאן לתמונה יש עומק הקובע את מספר הגוונים
)הפעם גווני האפור( האפשריים בתמונה .בדומה לתמונה צבעונית ,בתמונה בעומק xפיקסל בעל ערך 0
הוא שחור ,ופיקסל בעל ערך xהוא לבן .כל ערך בטווח מייצג גוון אפור )וכך מספר הגוונים האפשריים
בתמונה הוא .( x
לדוגמא בתמונה בגווני אפור בעומק 255כל פיקסל הוא מספר בין 0ו255 -
הפיקסל – 0שחור
הפיקסל – 255לבן
הפיקסל – 200אפור בהיר
הפיקסל – 50אפור כהה
אלגוריתם להמרת תמונה צבעונית לתמונה בגווני אפור -בכדי להמיר תמונה צבעונית לתמונה בגווני
אפור עלינו להחליט עבור כל פיקסל צבעוני באיזה פיקסל בגוון אפור הוא יוחלף .האלגוריתם בו נשתמש
הוא כזה הלוקח את הממוצע של ערכי R,Gו B-להיות ערך גוון האפור .כלומר גוון האפור של פיקסל
r + g +b
צבעוני r1,g1,b1יקבע להיות . 1 1 1 :שימו לב שהתמונה אותה מייצר האלגוריתם היא תמונה
3
בגווני אפור בעלת אותם המימדים ואותו העומק כמו התמונה הצבעונית.
עליכם לכתוב תוכנית המקבלת כפרמטר שם של קובץ תמונה צבעונית בפורמט PPMעם Magic
.P3 :Numberהתוכנית טוענת את התמונה לזיכרון ,ממירה אותה לתמונה בגווני אפור לפי האלגוריתם
שתואר לעיל ומייצרת קובץ בפורמט PGMעם P2 :Magic Numberמתאים לתמונה .שם קובץ הפלט
ללא הסיומת יהיה זהה לשם קובץ הקלט )ללא הסיומת( ,והסיומת של שם קובץ הפלט תהיה .PGM
- 18 -
ב .בסעיף זה נרצה להמיר תמונה בגווני אפור לתמונה בשחור לבן.
תמונה בשחור לבן היא מקרה פרטי של תמונה בגווני אפור .תמונה בשחור לבן היא תמונה בגווני אפור
בעומק .1נשים לב שבמקרה זה ישנם שני ערכים אפשריים בלבד לכל פיקסל 0 .המייצג את הצבע שחור
ו 1-המייצג את הצבע לבן.
אלגוריתם להמרת תמונה בגווני אפור לתמונה בשחור לבן -בכדי להמיר תמונה בגווני אפור לתמונה
בשחור לבן נצטרך להחליט עבור כל פיקסל מהתמונה בגווני אפור ,האם לצבעו בשחור או לצבעו בלבן.
מסתבר שהאלגוריתם הנאיבי אשר מחליף את המחצית הנמוכה של גווני האפור לשחור ואת המחצית
הגבוהה של גווני האפור ללבן ,משיג תוצאת גרועות )אתם מוזמנים אך לא חייבים לבדוק זאת(
אנחנו נשתמש באלגוריתם אחר ,האלגוריתם נקרא .dithering
הרציונל מאחורי האלגוריתם ditheringהוא מניעת מצב בו אזורים כהים יצבעו במלואם בשחור ואזורים
בהירים יצבעו במלואם בלבן ,האלגוריתם רוצה להוסיף מידה של "אקראיות" ,לפיה ישתלבו באזורים
הכהים גם נקודות לבנות ולהיפך.
בשלב הראשון מחלקים את גווני האפור ל k 2 -חלקים שווי גודל )פרט אולי לאחרון( ,לכל חלק מתאימים
מספר בין 0ל k 2 − 1 -לפי הסדר
בשלב השני מתאימים לכל פיקסל בתמונת גווני האפור המקורית מספר בין 0ל k 2 − 1 -לפי החלק אליו
הוא משתייך.
לדוגמא:
7 3 1 1 5 2 203 112 39 52 155 58
2 3 1 5 5 0 70 95 42 154 144 0
4 3 2 1 5 1 137 108 68 40 151 31
5 3 7 4 7 2 160 90 202 127 221 73
7 7 4 6 6 0 225 214 123 177 190 4
5 2 6 6 4 8 172 69 177 197 139 248
4 7 0 6 7 1 136 216 20 176 213 41
- 19 -
בשלב השלישי נעזרים במטריצה מסיכה ) (maskבגודל k × kשבה מופיעים המספרים מ 0 -עד
. k 2 − 1את המטריצה "פורשים" על התמונה שהתקבלה מהשלב הראשון ) ,(Bכלומר משכפלים ללא
חפיפות את המטריצה החל מהפינה השמאלית העליונה של התמונה לאורך ולרוחב.
בשלב הרביעי מייצרים תמונה בשחור לבן כך שהפיקסלים שערכם גדול מערך התא שהותאם להם
במסיכה יצבעו בלבן )ערך (1והפיקסלים שערכם קטן או שווה לערך התא שהותאם להם במסיכה יצבעו
בשחור )ערך .(0
- 20 -
עליכם לכתוב תוכנית המקבלת כפרמטר שם של קובץ תמונה בגווני אפור בפורמט PGMעם Magic
.P2 :Numberהתוכנית טוענת את התמונה לזיכרון ,ממירה אותה לתמונה בשחור לבן לפי האלגוריתם
שתואר לעיל ומייצרת קובץ )גם הוא בפורמט PGMעם (P2 :Magic Numberמתאים לתמונה .שם
קובץ הפלט ללא הסיומת יהיה זהה לשם קובץ הקלט )ללא הסיומת( אך בתוספת " ,"bwוהסיומת של שם
קובץ הפלט תשאר .PGM
הערה :במימוש האלגוריתם אין הכרח לעבור מעשית דרך כל השלבים .מימוש חכם יתייחס אליהם כאל
שלבים לוגיים בלבד) .לא באמת צריך ליצור את המטריצה ,Bואין צורך לשכפל מעשית מטריצה( ניתן
לממש את האלגוריתם במעבר אחד על התמונה ובעזרת פחות מ 15-שורות קוד ,חישבו איך(.
ג.
חזרו על הסעיפים א' ו-ב' אך הפעם במקום קובץ PPMעם P3 :Magic Numberהשתמשו בקובץ
PPMעם P6 :Magic Numberובמקום קובץ PGMעם P2 :Magic Numberהשתמשו בקובץ
PGMעם .P5 :Magic Number
- 21 -
PPM File Format
This note describes the format of PPM (Portable PixMap) file. This format is a
convenient (simple) method of saving a color image data.
A PPM file consists of two parts, the header and the image data. The header consists
of three parts that are delimitated by white space (usually linefeeds - '\n').
Header format:
The first part is a magic PPM identifier; it can be the string "P3" or the string "P6"
(not including the double quotes!).
The next part consists of the width and height of the image as ASCII numbers.
The last part of the header gives the maximum value of the color components (depth)
for the pixels. This value must be smaller than 256 and greater than 0.
In addition to the above required lines, a comment can be placed anywhere before the
depth starting with a "#" character, the comment extends to the end of the line.
The following are all valid PPM headers.
example 1: Header
P6 1024 788 255
example 2: Header
P6
1024 788
# A comment
255
example 3: Header
P3
1024 # the image width
788 # the image height
# A comment
15
example 4: PPM P3
P3
# example from the man page
4 4
15
0 0 0 0 0 0 0 0 0 15 0 15
0 0 0 0 15 7 0 0 0 0 0 0
0 0 0 0 0 0 0 15 7 0 0 0
15 0 15 0 0 0 0 0 0 0 0 0
If the PPM magic identifier is "P6" then the image data is stored in binary format, one
byte per color component (r,g,or b).
Comments can not appear in the image data section. Only one byte of a whitespace
may appear after the last header field, normally a '\n'.
- 22 -
PGM File Format
This format is identical to the above except it stores greyscale information, that is, one
value per pixel instead of 3 (r,g,b). The only difference in the header section is the magic
identifiers which are "P2" and "P5", these correspond to the ascii and binary form of the
data respectively.
PGM example
An example of a PGM file of type "P2" is given below
P2
24 7 #dimension
15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0
0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0
0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 23 -
Summary of the PPM/PGM file formats:
1. A "magic number" for identifying the file type. Consist of two ASCII
characters (one of the following):
"P6" – for PPM (color) Binary image data
"P3" – for PPM (color) ASCII image data
"P5" – for PGM (grayscale) Binary image data
"P2" – for PGM (grayscale) ASCII image data
2. Whitespaces (blanks, TABs, CRs, LFs).
3. A width, formatted as ASCII characters in decimal.
4. Whitespaces.
5. A height, again in ASCII decimal.
6. Whitespaces.
7. The maximum color value (depth), again in ASCII decimal. Must be less than
256 and more than zero.
8. A single whitespace character.
9. In P6 magic number: A block of Height rows, in order from top to bottom.
Each row consists of Width pixels, in order from left to right. Each pixel is a
triplet of red, green, and blue samples, in that order. Each sample is
represented in pure binary using one byte.
In P3 magic number: A block of Height rows, in order from top to bottom.
Each row consists of Width pixels, in order from left to right. Each pixel is a
triplet of red, green, and blue samples, in that order. Each sample is
represented as an ASCII decimal number. Each sample has white space before
and after it. There must be at least one character of white space between any
two samples, but there is no maximum. There is no particular separation of
one pixel from another -- just the required separation between the blue sample
of one pixel from the red sample of the next pixel.
In P5 magic number: A block of Height rows, in order from top to bottom.
Each row consists of Width pixels, in order from left to right. The gray level of
each pixel is represented in pure binary using exactly one byte.
In P2 magic number: A block of Height rows, in order from top to bottom.
Each row consists of Width pixels, in order from left to right. The gray level of
each pixel is represented as an ASCII decimal number. Each gray level has
white spaces before and after it. There must be at least one character of white
space between any two gray levels, but there is no maximum.
10. In general, characters from a "#" to the next end-of-line, before the depth line,
are comments and are ignored.
- 24 -
שאלה 3
נתונה ההגדרה הבאה של רשומה שמירת נתונים על תלמיד:
{typedef struct student
;char* name
;int average
;}STUDENT
א .כתבו תוכנית המקבלת כפרמטר שם של קובץ המכיל נתוני תלמידים עפ"י הפורמט לעיל .התוכנית
תיצור עבור קובץ התלמידים קובץ אינדקסים )קובץ המכיל נתונים של היסט יחסית לתחילת קובץ
התלמידים( ,כך שאם נעבור על ההיסטים ברצף נקבל את התלמידים בסדר לקסיקוגראפי עולה של שמות.
על שמו של קבוץ האינדקסים להיות השם של הקובץ המקורי בתוספת הסיומת ".".ind
הפונקציה מקבלת כקלט מחרוזת ,databaseהמייצגת שם של קובץ המכיל נתוני תלמידים )לפי
הפורמט שהוצג בתחילת השאלה( ,ומחרוזת ,studNameהמכילה שם של תלמיד.
על הפונקציה להחזיר את ממוצע הציונים של התלמיד ששמו studNameאו -1אם אין תלמיד כזה ב-
.database
הערות:
.1הניחו שהפונקציה הנ"ל נקראת רק אחרי שכבר נוצר קובץ אינדקסים ,כפי שהוגדר בסעיף א' ,עבור
הקובץ .database
.2הניחו שבקובץ ישנו לכל היותר תלמיד אחד עם השם .studName
.3שימו לב ליעילות זמן הריצה של הפונקציה אותה אתם כותבים.
- 25 -
ביטים
שאלה 1
חיפוש בספר טלפונים.
נניח כי לכל לקוח בספר טלפונים יש 2מחרוזות:
typedef struct client
{
;]char id[9 ”// “12345678
”char phone[11]; // “03:1234567
;}t_client
בשדה ת.ז .ישנן 8ספרות )ללא ספרת ביקורת( ובסוף ‘.’\0
בשדה טלפון יש שתי ספרות קידומת ,סימן הפרדה ‘) ’:נשים לב כי בטבלת asciiהוא מופיע מיד
לאחר ‘ ,(’9אח"כ 7ספרות המספר עצמו ו – ‘ ’\0בסוף.
בסה"כ נשמרים 20בתים ללקוח.
כל התווים המשתתפים במידע שנשמר ללקוח הינם עוקבים בטבלת .ascii
מדובר בתווים’:‘, ’9’…, ’2’,’1’,’0‘ :
ישנם בסה"כ 11תווים.
ניתן לקודד מחדש כל תו ב – 4סיביות באופן הבא:
0000 ’‘0
0001 ’‘1
0010 ’‘2
0011 ’‘3
0100 ’‘4
0101 ’‘5
0110 ’‘6
0111 ’‘7
1000 ’‘8
1001 ’‘9
1010 ’‘:
קידוד זה מאפשר לשמור את המידע הרצוי במבנה החדש .t_short_client
א .על מנת לצמצם את המקום הנדרש לייצג מחרוזות בת nתווים ,שבה מספר התווים השונים הוא לכל
היותר .16במקום שנידרש ל n -בתים כדי לשמור אותה עפ"י קוד ,asciiנצטמצם ל: n2 -
לכל תו נצמיד מספר בין 0ל 4) 15 -ביטים( .כך שבכל byteיהיו שני תווים.
תצטמצם להיות: למשל המחרוזת:
a c ''a
b a ''c
''b
''a
''\0
אם נסתכל בסדרת התווים השונים מהמחרוזת המקורית ,מסודרים לפי סדר הופעתם
הראשונה ,הערך שיוצמד לכל תו יהיה מיקומו בסדרה זו )החל מ.(0 -
למשל :אם המחרוזת המקורית היא:"acba" :
ל ,a -יוצמד הערך .0
ל ,c -יוצמד הערך .1
ל ,b -יוצמד הערך .2
0000 0001
0010 0000 ולכן המחרוזת המצומצמת תהיה:
כתבו תוכנית המקבלת כפרמטר שם של קובץ טקסט .ידוע שהקובץ הנ"ל מורכב משורות באורך זוגי של
תווים ,שבכל שורה יש לכל היותר 16תווים שונים.
על התוכנית להמיר קובץ זה לקובץ בינארי הבנוי לפי הפורמט הבא:
עבור כל שורה בקובץ הטקסט ,ישמרו בקובץ הבינארי המיוצר ,הנתונים הבאים:
.1מספר מטיפוס – unsigned charהמייצג את מספר התווים השונים בשורה.
.2רצף )באורך זה( של -charים – המכיל את סדרת התווים השונים בשורה ,מסודרים
לפי סדר הופעתם הראשונה באותה שורה.
.3מספר מטיפוס – unsigned intהמייצג את מספר הבתים בהם נשמרים התווים
המכווצים של השורה.
.4רצף )באורך זה( של בתים המכילים את הכווץ של השורה.
שמו של הקובץ המיוצר הוא כשמו של קובץ הקלט ,בתוספת " ".rdsבסוף.
- 27 -
למשל :נניח ש "[Link]" -הוא קובץ טקסט ,המכיל את שתי השורות:
acba
mbbmbmmb
אם תועבר לתוכנית ,כפרמטר בשורת ההפעלה ,המחרוזת " ,"[Link]יווצר הקובץ
" ."[Link]קובץ זה יכיל:
3
''a
''c
שורה I
''b
2
0000 0001
0010 0000
2
''m
''b
שורה II 4
0000 0001
0001 0000
0001 0000
0000 0001
- 28 -
ב .כעת נרצה לשחזר מחרוזת מכווצת המכילה לכל היותר 16תווים שונים ,למחרוזת רגילה.
כל בית במחרוזת המכווצת מכיל שני תווים מהמחרוזת הרגילה .כל תו תופס 4ביטים .ארבעת הביטים
השמאליים מייצגים את התו הראשון )שנשמר בבית הזה( ,וארבעת הביטים הימניים מייצגים את התו
השני )שנשמר בבית הזה(.
את השחזור נבצע בעזרת מערך codeהמכיל את כל התווים השונים של המחרוזת ,כל תו בדיוק פעם
אחת.
במחרוזת המכווצת במקום כל תו שומרים 4ביטים המייצגים את המיקום של אותו תו במערך .code
כתבו תוכנית המקבלת כפרמטר שם של קובץ בינארי השומר בצורה מכווצת ,בפורמט שיוגדר בהמשך,
שורות באורך זוגי של תווים ,שבכל שורה לכל היותר 16תווים שונים.
על התוכנית להמיר קובץ זה לקובץ טקסט .שמו של הקובץ המיוצר הוא כשמו של קובץ הקלט,
בתוספת " ".xpdבסוף.
ג .שירות הביטחון הכללי שומר שני קבצים עבור כל פעולה שהוא מבצע.
.1קובץ בינארי )שאותו ניתן אפילו לשלוח ב (mail -המחזיק בצורה מוצפנת שמות של הסוכנים
המשתתפים במבצע.
.2קובץ טקסט )שנשמר בכספת( המכיל את התמורות שבעזרתן ניתן לפענח את השמות המקודדים
בקובץ הבינארי.
הפונקציה מקבלת מערך Numbersשל מספרים שלמים שונים זה מזה ,ואת גודלו .sizeכמו כן היא
⎡⎢ sizeבתים .כל ביט במערך ,predמייצג נתון אחד של⎤ 8
מקבלת מערך predשל ביטים ,בגודל ⎥
המערך ,Numbersבאופן הבא:
הביט ה 0 -בבית ה 0 -של המערך ,predמייצג את הנתון באינדקס 0במערך .Numbers
הביט ה 1 -בבית ה 0 -של המערך ,predמייצג את הנתון באינדקס 1במערך .Numbers
הפונקציה תייצר ותחזיר את תת המערך המכיל אך ורק את הנתונים מהמערך ,Numbersאשר הביט
המתאים להם במערך ,predהוא .1
כמו כן ,הפונקציה תעדכן במשתנה הפלט new_sizeאת גודלו של תת המערך שייצרה.
8 4 2 6 30 22 28 32 20 26 24 10 16 14 18 12
pred
00101001
01001000
הערות:
• הניחו ש ,size -מספר הנתונים במערך ,Numbersמתחלק ב.8 -
• שימו לב כי בציור ,האינדקסים במערך המספרים מתקדמים משמאל לימין ,ואילו הביטים בכל בית
נספרים מימין לשמאל )מה LSB -אל ה.(MSB -
ב .השתמשו בפונקציה מסעיף א' ,על מנת לכתוב הפונקציה הבאה:
int* xorFilter(int* Numbers, int size, unsigned char* pred1,
;)unsigned char* pred2, int* new_size
הפונקציה מקבלת מערך Numbersשל מספרים שלמים שונים זה מזה ,ואת גודלו .sizeכמו כן היא
⎡⎢ sizeבתים .כל אחד
⎤ 8 מקבלת שני מערכים pred1ו pred2 -של ביטים ,כל אחד מהם בגודל ⎥
מהביטים ,בכל אחד מהמערכים pred1ו ,pred2 -מייצג נתון מסוים של המערך ,Numbersלפי
ההתאמה שתוארה בסעיף א'.
הפונקציה תייצר ותחזיר את תת המערך המכיל אך ורק את נתונים מהמערך .Numbersנתון מסוים
יופיע במערך התוצאה אם"ם בדיוק אחד מביו הביטים המתאימים לו במערך ,pred1ו ,pred2 -הוא
.1כמו כן ,הפונקציה תעדכן במשתנה הפלט new_sizeאת גודלו של תת המערך שייצרה.
הערה :הניחו ש ,size -מספר הנתונים במערך ,Numbersמתחלק ב.8 -
- 31 -
פויינטרים לפונקציות
שאלה 1
כתבו את הפונקציה:
;)void* scramble(void* arr, int ElemSize, int n, int* indArr
הפונקציה מקבלת:
• - arrמערך של איברים מטיפוס כלשהו.
• - ElemSizeגודל של כל אלמנט במערך arr
• - nמספר האיברים במערך .arr
• - indArrמערך המכיל תמורה של המספרים. 0,1,… , (n − 1) :
על הפונקציה ליצור מערך חדש שבו סדר האיברים נקבע על פי המערך indArrבאופן הבא:
האיבר ה i -במערך החדש יהיה האיבר שהאינדקס שלו במערך הישן הוא ].indArr[i
שאלה 2
נתון האלגוריתם הבא למימוש חיפוש בינארי של נתון במערך:
- 32 -
א .כתבו את הפונקציה הבאה:
int binSearch(void* Arr, int Size, int ElemSize,
;))*void* Item, int (*compare)(void*, void
על הפונקציה לממש אלגוריתם זה ,למערכים מטיפוסים שונים )מערכים של מחרוזות ,מערכים של
-intים וכו'( .הפונקציה מקבלת:
על הפונקציה להחזיר את הערך 1אם הנתון עליו מצביע Itemשווה לאחד מנתוני המערך ,או 0אחרת.
הערה:
הניחו שהפונקציה ,compareמקבלת כתובות של שני נתונים אותם היא משווה .ומחזירה:
• אפס -אם שני הפרמטרים מצביעים על נתונים שווים.
• מספר שלילי -אם הפרמטר הראשון מצביע על נתון קטן יותר מהנתון שמוצבע ע"י הפרמטר
השני.
• מספר חיובי -אם הפרמטר הראשון מצביע על נתון גדול יותר מהנתון שמוצבע ע"י הפרמטר
השני.
המקבלת מערך stringsשל מחרוזות ממוינות בסדר לקסיקוגרפי ,את גודלו ,sizeומחרוזת
נוספת .str
על הפונקציה להחזיר את הערך 1אם המחרוזת strמופיעה במערך ,stringsאו 0אחרת.
”“abcdefg
""good-luck
""mully
""stam
- 33 -
שאלה 3
מאגר של נתונים על מוצרים נשמר בקובץ בינארי .הקובץ בנוי בפורמט הבא:
.1מספר מטיפוס ,intהמייצג את מספר המוצרים בקובץ .נסמן את ערכו ב.N -
.2רצף באורך Nשל נתונים של מוצרים .כל מוצר מופיע בקובץ בפורמט הבא:
• מספר מטיפוס ,intהמייצג את מספר התווים בשמו של המוצר .נסמן את ערכו ב.len -
• רצף של lenתווים ,המכיל את שמו של המוצר )ללא ' '\0בסופו(.
• מספר מטיפוס ,intהמייצג את מחירו של המוצר.
על מנת למנוע שכפול קוד ביצירת שני קבצי האינדקס ,נגדיר פונקציה כללית ליצירת קובץ אינדקס
ממוין ,ונפעיל אותה פעמיים ליצירת כל אחד מקבצי האינדקס.
בסעיף א' של השאלה נגדיר את הפונקציה הכללית ליצירת קובץ אינדקס ממוין ,ובסעיף ב' נייצר את שני
קבצי האינדקס הרצויים לנו.
הפונקציה מקבלת מחרוזת DB_Nameהמכילה את שמו של קובץ בינארי .הקובץ מכיל מאגר של נתוני
מוצרים )לא ממוינים( בפורמט שהוגדר לעיל.
הפונקציה מייצרת קובץ אינדקסים ,בשם ,IndexFileNameהמכיל רצף של נתונים מטיפוס
,long intכל נתון בקובץ האינדקס ,מייצג היסט מתחילת קובץ המאגר ) (DB_Nameלתחילת נתוניו
של מוצר מסוים.
אם נעבור על קובץ המאגר ,לפי רצף ההיסטים בקובץ האינדקסים ,המיוצר ע"י הפונקציה ,נקבל את נתוני
המאגר ממוינים מהקטן לגדול ,עפ"י הסדר המושרה מפונקצית ההשוואה .compare
הערה :הפונקציה compareהינה פונקצית השוואה כללית ,המקבלת מצביעים לשני נתונים ומשווה
ביניהם .הפונקציה משרה סדר באופן הבא:
אם הנתון עליו מצביע הפרמטר הראשון קטן מזה שעליו מצביע הפרמטר השני ,היא תחזיר מספר •
שלילי.
אם הנתון עליו מצביע הפרמטר הראשון גדול מזה שעליו מצביע הפרמטר השני ,היא תחזיר מספר •
חיובי.
אם הנתון עליו מצביע הפרמטר הראשון שווה לזה שעליו מצביע הפרמטר השני ,היא תחזיר את •
הערך .0
הפונקציה sortמקבלת מצביע Arrלתחילת מערך ,מספר שלם elem_sizeהמייצג את גודלו של כל
נתון במערך ,ומספר שלם נוסף num_elemsהמייצג את מספר הנתונים במערך.
הפונקציה ממיינת את הנתונים במערך ,Arrעפ"י הסדר המושרה מפונקצית ההשוואה הכללית
.compare
- 34 -
ב .השתמשו בפונקציה שכתבתם בסעיף א' ,על מנת לכתוב את שתי הפונקציות הבאות:
כל אחת מהפונקציות מקבלת שם של קובץ DB_Nameהמכיל מאגר של נתונים על מוצרים ,בפורמט
שפורט בתחילת השאלה .כל אחת מהפונקציות מייצרת קובץ אינדקסים בשם ) indexFileNameלפי
הפורמט שהוגדר בסעיף א'(.
אם נעבור על קובץ המאגר ,לפי רצף ההיסטים בקובץ אשר מייצרת הפונקציה הראשונה ,נקבל את נתוני
המאגר ממוינים לפי שם המוצרים ,מהקטן לגדול.
אם נעבור על קובץ המאגר ,לפי רצף ההיסטים בקובץ אשר מייצרת הפונקציה השנייה ,נקבל את נתוני
המאגר ממוינים לפי מחיר המוצרים ,מהקטן לגדול.
- 35 -