מתכונת 7 במדעי המחשב - יסודות מדעי המחשב 899371
1–2 יח"ל · שאלון 899371 · 6 שאלות · 2:30 שעות · פתרון מלא לכל סעיף
מבחן מתכונת במדעי המחשב, יסודות מדעי המחשב, במבנה של בחינת הבגרות. כל שאלה בו בנויה כמו שאלה מבגרות אחרת. לכל סעיף יש תשובה ופתרון מלא, וכל קוד מופיע ב-Java וב-C#. פתרו בזמן של הבחינה, ורק אחר כך פתחו את הפתרונות.
הוראות הבחינה
א. משך הבחינה: שעתיים וחצי.
ב. מבנה השאלון ומפתח ההערכה: בשאלון זה שני פרקים.
פרק ראשון – (20×2) – 40 נקודות
פרק שני – (30×2) – 60 נקודות
סך הכול – 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנוּת.
ד. הוראה מיוחדת:
את כל התוכניות שיש לכתוב בשפת מחשב כתבו בשפה אחת בלבד – Java או C#.
הערה: לא יוּרדוּ נקודות אם תכתבו בתוכניות אות גדולה במקום אות קטנה או להפך.
יש לכתוב במחברת הבחינה בלבד. יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
השאלות
בשאלון זה שני פרקים.
יש לענות על שאלות משני הפרקים, לפי ההוראות בכל פרק.
הערה: בכל שאלה שנדרשת בה קליטה, אין צורך לבדוק את תקינות הקלט.
לפותרים בשפת Java: בכל שאלה שנדרשת בה קליטה, הניחו שבתוכנית כתובה ההוראה:
Scanner scan = new Scanner (System.in);
פרק ראשון (40 נקודות)
ענו על שתיים מן השאלות 1–3 (לכל שאלה – 20 נקודות).
שאלה 1 · מעקב – ספרת האחדות מול ספרת העשרות (20 נקודות)
נתון מערך arr , המכיל מספרים שלמים חיוביים.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|---|
| arr | 47 | 1302 | 85 | 9 | 560 | 2318 | 71 |
לפניכם קטע תוכנית, הכתוב בשפות Java ו־ C# .
Java
int count=0;
for (int i=0; i<arr.length; i++)
{
int a=arr[i]%10;
int b=arr[i]/10%10;
int swapped=a*10+b;
if (swapped>arr[i]%100)
count++;
}C#
int count=0;
for (int i=0; i<arr.Length; i++)
{
int a=arr[i]%10;
int b=arr[i]/10%10;
int swapped=a*10+b;
if (swapped>arr[i]%100)
count++;
}עקבו בעזרת טבלת מעקב אחר ביצוע קטע התוכנית עבור המערך arr , ורשמו את ערך המשתנה count לאחר ביצוע קטע התוכנית.
בטבלת המעקב יש לכלול עמודה עבור כל אחד מן המשתנים האלה: count , i , a , b , swapped .
כתבו דוגמה למערך arr בגודל 4 המכיל מספרים שלמים חיוביים (גדולים מ־ 0) שבסיום קטע התוכנית ערכו של המשתנה count יישאר 0 .
כתבו דוגמה למערך arr בגודל 4 המכיל מספרים שלמים חיוביים שאף אחד מהם אינו חד־ספרתי, כך שבסיום קטע התוכנית ערכו של המשתנה count יהיה שווה ל־ 4 .
◂ פתרון מלא לשאלה 1
סעיף א
count = 4 (המספרים 47 , 1302 , 9 , 2318 – שבהם ספרת האחדות גדולה מספרת העשרות).
מה נדרש: לעקוב אחר קטע התוכנית עבור המערך הנתון ולמצוא את ערך count בסוף.
רעיון: a היא ספרת האחדות של arr[i], ו־ b היא ספרת העשרות שלו (arr[i]/10 מוריד את ספרת האחדות, ו־ %10 לוקח את הספרה הימנית של התוצאה). swapped הוא המספר הדו־ספרתי שמתקבל מהחלפת שתי הספרות האלה, ו־ arr[i]%100 הוא המספר שבנוי משתי הספרות הימניות בסדר המקורי. לכן התנאי מתקיים בדיוק כאשר ספרת האחדות גדולה מספרת העשרות (a > b).
פתרון – טבלת מעקב (העמודה arr[i]%100 נוספה לנוחות):
| i | arr[i] | a | b | swapped | arr[i]%100 | swapped > arr[i]%100 ? | count |
|---|---|---|---|---|---|---|---|
| 0 | |||||||
| 0 | 47 | 7 | 4 | 74 | 47 | כן | 1 |
| 1 | 1302 | 2 | 0 | 20 | 2 | כן | 2 |
| 2 | 85 | 5 | 8 | 58 | 85 | לא | 2 |
| 3 | 9 | 9 | 0 | 90 | 9 | כן | 3 |
| 4 | 560 | 0 | 6 | 6 | 60 | לא | 3 |
| 5 | 2318 | 8 | 1 | 81 | 18 | כן | 4 |
| 6 | 71 | 1 | 7 | 17 | 71 | לא | 4 |
| 7 | (התנאי i<7 אינו מתקיים – יציאה מהלולאה) | 4 |
בסיום הקטע: count = 4.
בדיקה: על המערך מתקבל count = 4.
טעות נפוצה: לטעות במספרים שאינם דו־ספרתיים. במספר החד־ספרתי 9 ספרת העשרות היא 0 , ולכן swapped = 90 > 9 – והוא נספר. במספר 1302 משתתפות רק שתי הספרות הימניות: a = 2 , b = 0 , swapped = 20 > 2 .
סעיף ב
למשל arr = {21, 30, 99, 54} (בכל מספר ספרת האחדות קטנה מספרת העשרות או שווה לה).
מה נדרש: מערך בגודל 4 של מספרים חיוביים שעבורו count נשאר 0.
רעיון: count גדל רק כאשר ספרת האחדות גדולה מספרת העשרות. די לבחור מספרים שבהם ספרת האחדות קטנה או שווה לספרת העשרות.
פתרון: למשל
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| arr | 21 | 30 | 99 | 54 |
21: 12 > 21 לא; 30: 3 > 30 לא; 99: 99 > 99 לא (השוואה חזקה); 54: 45 > 54 לא. לכן count נשאר 0 .
בדיקה: על {21, 30, 99, 54} מתקבל count = 0 . (יש עוד תשובות נכונות רבות.)
טעות נפוצה: לשים במערך מספר חד־ספרתי. בכל מספר חד־ספרתי חיובי ספרת העשרות היא 0 , ולכן הוא תמיד נספר – למשל {5, 5, 5, 5} נותן count = 4 .
סעיף ג
למשל arr = {12, 389, 1045, 67} (בכל מספר ספרת האחדות גדולה מספרת העשרות).
מה נדרש: מערך בגודל 4 , בלי מספרים חד־ספרתיים, שעבורו count = 4 – כלומר כל ארבעת המספרים נספרים.
רעיון: צריך שבכל מספר ספרת האחדות תהיה גדולה (ממש) מספרת העשרות. שאר הספרות (מאות, אלפים) אינן משפיעות.
פתרון: למשל
| 0 | 1 | 2 | 3 | |
|---|---|---|---|---|
| arr | 12 | 389 | 1045 | 67 |
| i | arr[i] | a | b | swapped | count |
|---|---|---|---|---|---|
| 0 | 12 | 2 | 1 | 21 | 1 |
| 1 | 389 | 9 | 8 | 98 | 2 |
| 2 | 1045 | 5 | 4 | 54 | 3 |
| 3 | 67 | 7 | 6 | 76 | 4 |
בדיקה: על {12, 389, 1045, 67} מתקבל count = 4 .
שאלה 2 · ערבוב מושלם של חפיסת קלפים – שילוב שני חצאי מערך (20 נקודות)
ממשו את הפעולה shuffle בשפת Java או Shuffle בשפת C# :
Java – public static void shuffle (int[] arr)
C# – public static void Shuffle (int[] arr)
קוסם מבצע "ערבוב מושלם" של חפיסת קלפים: הוא מחלק את החפיסה לשני חצאים שווים ומשלב אותם כך שהקלפים של שני החצאים מופיעים לסירוגין.
במערך arr שמתקבל רשומים מספרי הקלפים לפי סדרם בחפיסה. מספר האיברים במערך זוגי.
הפעולה מסדרת מחדש את המערך arr כך: בתא 0 – האיבר הראשון של החצי הראשון, בתא 1 – האיבר הראשון של החצי השני, בתא 2 – האיבר השני של החצי הראשון, בתא 3 – האיבר השני של החצי השני, וכן הלאה. הסדר של האיברים בתוך כל חצי (בינם לבין עצמם) יישאר באותו הסדר שבו הם היו לפני הפעולה.
דוגמה:
בעבור המערך arr שלפניכם:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|---|
| arr | 11 | 3 | 8 | 13 | 2 | 9 | 5 | 1 |
המערך arr ייראה כך בסיום הפעולה:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|---|
| arr | 11 | 2 | 3 | 9 | 8 | 5 | 13 | 1 |
הסבר: החצי הראשון של המערך הוא 11, 3, 8, 13 והחצי השני הוא 2, 9, 5, 1. הפעולה שילבה את שני החצאים לסירוגין, החל באיבר הראשון של החצי הראשון.
ממשו את הפעולה shuffle בשפת Java או Shuffle בשפת C#, לפי התיאור שלמעלה.
◂ פתרון מלא לשאלה 2
פתרון
half = arr.length / 2; במערך עזר: temp[2·i] = arr[i] ו-temp[2·i + 1] = arr[half + i] לכל i < half; בסוף מעתיקים את temp חזרה ל-arr.
מה נדרש
לשלב את שני חצאי המערך לסירוגין (קודם מהחצי הראשון) ולשמור את התוצאה ב-arr עצמו. הפעולה לא מחזירה ערך.
רעיון
נסמן half = arr.length / 2. החצי הראשון הוא התאים 0 … half − 1, והחצי השני הוא התאים half … arr.length − 1.
האיבר ה-i של החצי הראשון (arr[i]) צריך להגיע לתא הזוגי 2·i, והאיבר ה-i של החצי השני (arr[half + i]) צריך להגיע לתא האי-זוגי שאחריו, 2·i + 1.
אי אפשר לכתוב ישר לתוך arr – היינו דורסים איברים שעוד לא הועברו. לכן בונים את התוצאה במערך עזר temp, ובסוף מעתיקים אותו חזרה ל-arr.
פתרון
Java
public static void shuffle(int[] arr)
{
int half = arr.length / 2;
int[] temp = new int[arr.length];
for (int i = 0; i < half; i++)
{
temp[2 * i] = arr[i]; // קלף מהחצי הראשון – במקום זוגי
temp[2 * i + 1] = arr[half + i]; // קלף מהחצי השני – במקום אי-זוגי
}
for (int i = 0; i < arr.length; i++)
{
arr[i] = temp[i];
}
}C#
public static void Shuffle(int[] arr)
{
int half = arr.Length / 2;
int[] temp = new int[arr.Length];
for (int i = 0; i < half; i++)
{
temp[2 * i] = arr[i]; // קלף מהחצי הראשון – במקום זוגי
temp[2 * i + 1] = arr[half + i]; // קלף מהחצי השני – במקום אי-זוגי
}
for (int i = 0; i < arr.Length; i++)
{
arr[i] = temp[i];
}
}בדיקה
על מערך הדוגמה {11, 3, 8, 13, 2, 9, 5, 1}: half = 4.
| i | arr[i] ← temp[2i] | arr[half + i] ← temp[2i + 1] |
|---|---|---|
| 0 | 11 ← temp[0] | 2 ← temp[1] |
| 1 | 3 ← temp[2] | 9 ← temp[3] |
| 2 | 8 ← temp[4] | 5 ← temp[5] |
| 3 | 13 ← temp[6] | 1 ← temp[7] |
temp = {11, 2, 3, 9, 8, 5, 13, 1}, והוא מועתק ל-arr ✓
גם {1, 2} ← {1, 2} ו-{1, 2, 3, 4, 5, 6} ← {1, 4, 2, 5, 3, 6} עובדים. (עובדה משעשעת: שלושה "ערבובים מושלמים" של 8 קלפים מחזירים את החפיסה לסדר המקורי שלה.)
טעות נפוצה: לבצע החלפות (swap) בתוך arr בלי מערך עזר – החלפה כזאת מזיזה איברים שעוד לא הגיעו למקומם ומשבשת את הסדר. טעות נוספת: להריץ את הלולאה הראשונה עד arr.length במקום עד half – אז arr[half + i] חורג מגבולות המערך.
public static void shuffle(int[] arr)
{
int half = arr.length / 2;
int[] temp = new int[arr.length];
for (int i = 0; i < half; i++)
{
temp[2 * i] = arr[i]; // קלף מהחצי הראשון – במקום זוגי
temp[2 * i + 1] = arr[half + i]; // קלף מהחצי השני – במקום אי-זוגי
}
for (int i = 0; i < arr.length; i++)
{
arr[i] = temp[i];
}
}שאלה 3 · השוואת גדילי DNA – מחרוזות (20 נקודות)
גדיל DNA מיוצג על ידי מחרוזת המורכבת מן האותיות A , C , G , T בלבד (כל אות יכולה להופיע במחרוזת כמה פעמים).
חוקרת משווה שני גדילים תו אחר תו: האות שבמקום i בגדיל הראשון מושווית לאות שנמצאת באותו מקום בגדיל השני.
כל זוג אותיות מקבל ציון:
– ציון "זהה" ניתן כאשר שתי האותיות שוות.
– ציון "משלים" ניתן כאשר שתי האותיות הן זוג משלים: A ו־ T (בסדר כלשהו), או C ו־ G (בסדר כלשהו).
– ציון "שונה" ניתן בכל מקרה אחר.
לדוגמה: בעבור הגדיל "ACGTTAG" והגדיל "ACCAAGT" :
| אינדקס | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| גדיל ראשון | A | C | G | T | T | A | G |
| גדיל שני | A | C | C | A | A | G | T |
שני ציוני "זהה" (באינדקסים 0 ו־ 1).
שלושה ציוני "משלים" (באינדקס 2 – G ו־ C , ובאינדקסים 3 ו־ 4 – T ו־ A).
שני ציוני "שונה" (באינדקס 5 – A ו־ G , ובאינדקס 6 – G ו־ T).
כתבו פעולה חיצונית ששמה compareStrands בשפת Java או CompareStrands בשפת C# , המקבלת שני פרמטרים:
גדיל ראשון – strand1 , וגדיל שני – strand2 .
הניחו ששתי המחרוזות תקינות (כלומר מופיעות בהן רק האותיות A , C , G , T).
אם האורך של שתי המחרוזות שונה, הפעולה תדפיס הודעת שגיאה "Length Error" .
אם האורך של שתי המחרוזות זהה, הפעולה תדפיס את מספר ציוני ה"זהה", מספר ציוני ה"משלים" ומספר ציוני ה"שונה" (כל הדפסה בשורה חדשה).
◂ פתרון מלא לשאלה 3
פתרון
לכל i משווים את strand1.charAt(i) ל־ strand2.charAt(i): שוות → זהה; A/T או C/G → משלים; אחרת → שונה. בדוגמה: 2, 3, 2
מה נדרש: פעולה המדפיסה "Length Error" אם האורכים שונים, ואחרת את מספר ה"זהה", ה"משלים" וה"שונה" – כל אחד בשורה.
רעיון: עוברים באינדקס i אחד על שתי המחרוזות יחד (אורכן שווה), ולוקחים c1 = strand1.charAt(i), c2 = strand2.charAt(i):
את הבדיקה "זהה" עושים ראשונה; כך בבדיקת "משלים" כבר ידוע שהאותיות שונות.
פתרון: הקוד המלא – בלשונית Java / C#.
בדיקה:
| strand1 | strand2 | פלט |
|---|---|---|
| ACGTTAG | ACCAAGT | 2, 3, 2 (כמו בדוגמה) |
| ACGT | ACG | Length Error |
| ACGT | ACGT | 4, 0, 0 |
| ACGT | TGCA | 0, 4, 0 |
| AACC | CCAA | 0, 0, 4 |
טעות נפוצה: לבדוק רק כיוון אחד של הזוג (למשל A ו־ T אבל לא T ו־ A) – אז באינדקס 3 בדוגמה (T ו־ A) יינתן בטעות ציון "שונה".
public static void compareStrands(String strand1, String strand2)
{
if (strand1.length() != strand2.length())
{
System.out.println("Length Error");
}
else
{
int same = 0, comp = 0, diff = 0;
for (int i = 0; i < strand1.length(); i++)
{
char c1 = strand1.charAt(i);
char c2 = strand2.charAt(i);
if (c1 == c2)
same++;
else if ((c1 == 'A' && c2 == 'T') || (c1 == 'T' && c2 == 'A') ||
(c1 == 'C' && c2 == 'G') || (c1 == 'G' && c2 == 'C'))
comp++;
else
diff++;
}
System.out.println(same);
System.out.println(comp);
System.out.println(diff);
}
}פרק שני (60 נקודות)
ענו על שתיים מן השאלות 4–6 (לכל שאלה – 30 נקודות).
שאלה 4 · יומן צלילות – מערך עצמים (30 נקודות)
מועדון צלילה שומר בעבור כל צולל יומן צלילות.
נתונה המחלקה Dive המייצגת צלילה אחת ולה שתי תכונות: עומק הצלילה במטרים – depth, ומשך הצלילה בדקות – minutes (שתיהן מספרים שלמים וחיוביים).
public class Dive{
private int depth;
private int minutes;
}בנוסף, נתונה המחלקה DiveLog המייצגת יומן צלילות של צולל ולה שתי תכונות: שם הצולל – diverName, ומערך של עצמים dives מטיפוס Dive בגודל מספר הצלילות שהצולל ביצע.
public class DiveLog{
private String diverName;
private Dive[] dives;
}הניחו שקיימות פעולות get ו־set בשפת Java ופעולות Get ו־Set בשפת C# בעבור כל התכונות בשתי המחלקות.
לפניכם ממשק חלקי של המחלקה DiveLog:
| תיאור הפעולה | כותרת הפעולה |
|---|---|
| פעולה בונה המקבלת את שם הצולל ואת מספר הצלילות שביצע, ומאתחלת את התכונות. המערך dives מאותחל למערך ריק בגודל num | public DiveLog(String name, int num) |
| פעולה המחזירה את סכום משכי הצלילות (בדקות) של כל הצלילות ביומן. | Java – public int totalMinutes()<br>C# – public int TotalMinutes() |
| פעולה המחזירה true אם הצולל הוא "צולל מתקדם", אחרת מחזירה false. צולל מתקדם הוא צולל שביצע 10 צלילות לפחות, וסך משכי הצלילות שלו הוא 600 דקות לפחות. | Java – public boolean isAdvanced()<br>C# – public bool IsAdvanced() |
ממשו את הפעולה הבונה של המחלקה DiveLog.
ממשו את הפעולה isAdvanced (בשפת C#: IsAdvanced) במחלקה DiveLog.
ניתן להשתמש בפעולה totalMinutes של המחלקה DiveLog מבלי לממש אותה.
הניחו כי איברי המערך dives שונים מ־null.
כתבו פעולה חיצונית ששמה countAdvanced (בשפת C#: CountAdvanced) המקבלת מערך של עצמים – club מטיפוס DiveLog, המייצג את יומני הצלילות של חברי המועדון. הפעולה תדפיס את שמות הצוללים המתקדמים, ותחזיר את מספר הצוללים המתקדמים.
חובה להשתמש בפעולה isAdvanced של המחלקה DiveLog.
הניחו כי איברי המערכים club ו־dives שונים מ־null.
◂ פתרון מלא לשאלה 4
סעיף א
diverName = name; dives = new Dive[num];
מה נדרש: לממש את הפעולה הבונה DiveLog(name, num).
רעיון: הפעולה הבונה מציבה את השם בתכונה diverName ויוצרת מערך חדש של num הפניות לעצמים מטיפוס Dive. המערך "ריק": כל תאיו מאותחלים ל־null, כי עדיין אין בו צלילות.
פתרון: הקוד המלא – בלשונית Java/C#.
בדיקה: אחרי new DiveLog("Test", 3) התקבל (בשתי השפות): diverName = "Test", אורך המערך dives הוא 3, ו־dives[0] הוא null.
טעות נפוצה: לכתוב Dive[] dives = new Dive[num]; – זו הצהרה על משתנה מקומי חדש, והתכונה dives נשארת null.
public DiveLog(String name, int num)
{
this.diverName = name;
this.dives = new Dive[num];
}סעיף ב
return dives.length >= 10 && totalMinutes() >= 600;
מה נדרש: להחזיר true אם הצולל ביצע 10 צלילות לפחות וגם סך משכי הצלילות שלו 600 דקות לפחות.
רעיון: מספר הצלילות הוא אורך המערך dives (המערך בגודל מספר הצלילות). את סך הדקות מקבלים מהפעולה totalMinutes של העצם הנוכחי, בלי לממש אותה. שני התנאים חייבים להתקיים יחד, ולכן מחברים אותם ב־&&.
פתרון: הקוד המלא – בלשונית Java/C#.
בדיקה:
| צולל | מספר צלילות | סך דקות | isAdvanced |
|---|---|---|---|
| Liron | 12 | 600 | true |
| Omer | 9 | 720 | false |
| Shani | 10 | 600 | true |
| Itay | 15 | 585 | false |
| Gal | 20 | 900 | true |
טעות נפוצה: להשתמש ב־> במקום ב־>= ("לפחות" כולל את הגבול: 10 צלילות ו־600 דקות כבר מספיקים), או לבדוק רק אחד משני התנאים (Omer צלל 720 דקות, אבל רק 9 צלילות).
public boolean isAdvanced()
{
return this.dives.length >= 10 && this.totalMinutes() >= 600;
}סעיף ג
לכל i: אם club[i].isAdvanced() – מדפיסים club[i].getDiverName() ומגדילים מונה; בסוף מחזירים את המונה.
מה נדרש: פעולה חיצונית (סטטית, מחוץ למחלקה DiveLog) שמדפיסה את שמות הצוללים המתקדמים ומחזירה כמה כאלה יש.
רעיון: מונה count שמתחיל ב־0. עוברים על כל תאי המערך club; לכל יומן שואלים club[i].isAdvanced(). אם התשובה true – מדפיסים את שם הצולל בעזרת פעולת ה־get של diverName ומגדילים את המונה. אחרי הלולאה מחזירים את count. הפעולה חיצונית, ולכן אין לה גישה ישירה לתכונה הפרטית diverName.
פתרון: הקוד המלא – בלשונית Java/C#.
בדיקה: על מערך של חמשת היומנים מהטבלה בסעיף ב מודפס:
Liron
Shani
Galוהפעולה החזירה 3.
טעות נפוצה: לכתוב return בתוך הלולאה (הפעולה תסתיים אחרי הצולל המתקדם הראשון), או לגשת ל־club[i].diverName – התכונה פרטית, וחייבים getDiverName() (ב־C#: GetDiverName()).
public static int countAdvanced(DiveLog[] club)
{
int count = 0;
for (int i = 0; i < club.length; i++)
{
if (club[i].isAdvanced())
{
System.out.println(club[i].getDiverName());
count++;
}
}
return count;
}שאלה 5 · רשימת השמעה ברדיו – Track (30 נקודות)
נתונה המחלקה Track – שיר ברשימת ההשמעה של תחנת רדיו אזורית, ולה ארבע תכונות:
לדוגמה, לשיר שאורכו 3:45 (שלוש דקות וארבעים וחמש שניות) יש min = 3 ו־ sec = 45 .
הניחו שהפעולות get/Get ו־ set/Set קיימות עבור תכונות המחלקה.
הערה: לאותו אמן (artist) יכולים להיות כמה שירים ברשימה.
נתון מערך שירים מלא – arr מטיפוס Track של רשימת ההשמעה השבועית. המערך אינו ממוין.
כתבו במחלקה Track פעולה פנימית ששמה isShorter בשפת Java או IsShorter בשפת C# , המקבלת שיר אחר – other (מטיפוס Track). הפעולה מחזירה true אם השיר הנוכחי קצר יותר מן השיר האחר (other), ואחרת מחזירה false .
כתבו פעולה חיצונית ששמה shortest בשפת Java או Shortest בשפת C# המקבלת את המערך arr , ומדפיסה את קוד האמן (artist) של השיר הקצר ביותר ברשימה.
הניחו שיש רק שיר אחד המקיים תנאי זה.
הערה: חובה להיעזר בפעולה שכתבתם בסעיף א(1).
כתבו פעולה חיצונית ששמה totalPlays בשפת Java או TotalPlays בשפת C# המקבלת את המערך arr וקוד של אמן – artist . הפעולה מחזירה את מספר ההשמעות סך הכול של כל השירים של האמן artist ברשימה.
לדוגמה: אם לאמן artist יש ברשימה שני שירים, האחד הושמע 40 פעמים והשני 30 פעמים, יוחזר 70 .
כתבו פעולה חיצונית ששמה topArtist בשפת Java או TopArtist בשפת C# המקבלת את המערך arr . הפעולה תחזיר את קוד האמן (artist) שמספר ההשמעות סך הכול של כל שיריו הוא הגדול ביותר.
הניחו שיש רק אמן אחד המקיים תנאי זה.
הערה: חובה להיעזר בפעולה שכתבתם בסעיף ב(1).
◂ פתרון מלא לשאלה 5
סעיף א(1)
return min·60 + sec < other.getMin()·60 + other.getSec();
מה נדרש: להשוות את אורך השיר הנוכחי לאורך השיר other.
רעיון: ממירים כל אורך למספר אחד – סך השניות: min × 60 + sec. כך ההשוואה היא השוואה רגילה של שני מספרים, ולא צריך לטפל בנפרד במקרה שבו הדקות שוות.
פתרון:
public boolean isShorter(Track other)
{
int myLength = this.min * 60 + this.sec;
int otherLength = other.getMin() * 60 + other.getSec();
return myLength < otherLength;
}בדיקה: 3:45 מול 4:05 → true; 4:05 מול 3:45 → false; 2:58 מול 3:02 → true; 3:02 מול 2:58 → false (אף ש־ 2 < 58); שני שירים באורך 3:45 → false.
טעות נפוצה: להשוות רק את השניות, או לכתוב min < other.getMin() && sec < other.getSec() – עבור 2:58 מול 3:02 התנאי הזה נותן false אף שהשיר הראשון קצר יותר.
public boolean isShorter(Track other)
{
int myLength = this.min * 60 + this.sec;
int otherLength = other.getMin() * 60 + other.getSec();
return myLength < otherLength;
}סעיף א(2)
מחפשים את השיר הקצר ביותר (best) בעזרת isShorter ומדפיסים best.getArtist().
מה נדרש: למצוא את השיר הקצר ביותר ולהדפיס את קוד האמן שלו.
רעיון: חיפוש מינימום על עצמים: שומרים הפניה best לשיר הקצר ביותר עד כה (מתחילים ב־ arr[0]). לכל שיר הבא, אם arr[i].isShorter(best) – מעדכנים את best. בסוף מדפיסים את קוד האמן של best.
פתרון:
public static void shortest(Track[] arr)
{
Track best = arr[0];
for (int i = 1; i < arr.length; i++)
{
if (arr[i].isShorter(best))
best = arr[i];
}
System.out.println(best.getArtist());
}בדיקה: מערך של 5 שירים: (12, 3:45), (7, 4:05), (12, 2:58), (31, 3:02), (7, 5:30) – מודפס 12 (השיר 2:58). במערך (7, 5:30), (7, 4:05), (31, 3:02) מודפס 31.
טעות נפוצה: לשמור רק את קוד האמן במקום את השיר עצמו – אז אי אפשר לקרוא ל־ isShorter על "הקצר ביותר עד כה".
public static void shortest(Track[] arr)
{
Track best = arr[0];
for (int i = 1; i < arr.length; i++)
{
if (arr[i].isShorter(best))
best = arr[i];
}
System.out.println(best.getArtist());
}סעיף ב(1)
סכום getPlays() של כל השירים שבהם getArtist() == artist.
מה נדרש: לסכום את ההשמעות של כל השירים של אמן מסוים.
רעיון: צבירה עם תנאי: עוברים על כל המערך (המערך אינו ממוין, ושירי האמן יכולים להופיע בכל מקום), ולכל שיר של האמן artist מוסיפים את getPlays() לסכום.
פתרון:
public static int totalPlays(Track[] arr, int artist)
{
int sum = 0;
for (int i = 0; i < arr.length; i++)
{
if (arr[i].getArtist() == artist)
sum = sum + arr[i].getPlays();
}
return sum;
}בדיקה: במערך חמשת השירים (ההשמעות: 40, 25, 30, 60, 50): אמן 12 → 70, אמן 7 → 75, אמן 31 → 60, אמן שאינו ברשימה → 0.
public static int totalPlays(Track[] arr, int artist)
{
int sum = 0;
for (int i = 0; i < arr.length; i++)
{
if (arr[i].getArtist() == artist)
sum = sum + arr[i].getPlays();
}
return sum;
}סעיף ב(2)
מקסימום של totalPlays(arr, arr[i].getArtist()) על כל i; מחזירים את קוד האמן שבו התקבל.
מה נדרש: למצוא את האמן שסך ההשמעות של שיריו הוא הגדול ביותר.
רעיון: לכל שיר במערך מחשבים בעזרת totalPlays את סך ההשמעות של האמן שלו, ומחפשים מקסימום על הערכים האלה. אמן עם כמה שירים יחושב כמה פעמים – זה לא משנה את התוצאה (הסכום שלו זהה בכל פעם). מתחילים מהאמן של arr[0].
פתרון:
public static int topArtist(Track[] arr)
{
int bestArtist = arr[0].getArtist();
int bestPlays = totalPlays(arr, bestArtist);
for (int i = 1; i < arr.length; i++)
{
int plays = totalPlays(arr, arr[i].getArtist());
if (plays > bestPlays)
{
bestPlays = plays;
bestArtist = arr[i].getArtist();
}
}
return bestArtist;
}בדיקה: במערך חמשת השירים: אמן 12 → 70, אמן 7 → 75, אמן 31 → 60, ולכן הוחזר 7. במערך (31, 60), (12, 40), (7, 25), (12, 30) הוחזר 12. במערך שבו לאמן 5 שיר אחד עם 90 השמעות ולאמן 8 שני שירים עם 50 ו־ 45 הוחזר 8 (95 > 90).
טעות נפוצה: לחפש את השיר עם הכי הרבה השמעות (getPlays() הגדול ביותר) – זה לא בהכרח האמן עם הסכום הגדול ביותר (בדוגמה האחרונה השיר הבודד של אמן 5 "מנצח" כל שיר של אמן 8).
public static int topArtist(Track[] arr)
{
int bestArtist = arr[0].getArtist();
int bestPlays = totalPlays(arr, bestArtist);
for (int i = 1; i < arr.length; i++)
{
int plays = totalPlays(arr, arr[i].getArtist());
if (plays > bestPlays)
{
bestPlays = plays;
bestArtist = arr[i].getArtist();
}
}
return bestArtist;
}שאלה 6 · הצפנה בהזזת אותיות לפי מערך מפתח
כדי להצפין מסר המורכב מאותיות קטנות באנגלית בלבד (a–z), מזיזים כל אות במסר קדימה באלף־בית מספר מקומות.
מספר המקומות יכול להיות שונה לכל אות, והוא נקבע לפי "מערך מפתח": גודל מערך המפתח הוא כאורך המסר, ובכל תא בו מספר שלם בין 0 ל־ 25 . האות שבאינדקס i במסר מוזזת קדימה מספר מקומות כערך התא שבאינדקס i במערך המפתח.
ההזזה היא מעגלית: אחרי האות z באה שוב האות a .
לדוגמה: המסר code עם מערך המפתח שלפניכם מוצפן למסר drdd .
| 0 | 1 | 2 | 3 |
|---|---|---|---|
| 1 | 3 | 0 | 25 |
הסבר: האות c זזה מקום אחד ונהיית d , האות o זזה 3 מקומות ונהיית r , האות d לא זזה, והאות e זזה 25 מקומות – אחרי z ממשיכים מ־ a – ונהיית d .
רשמו את מערך המפתח שבעזרתו הוצפן המסר zebra למסר agcxb .
כתבו פעולה חיצונית ששמה decode בשפת Java או Decode בשפת C# , המקבלת מחרוזת מוצפנת – str ומערך מפתח – arr . הפעולה תחזיר את המסר המקורי.
◂ פתרון מלא לשאלה 6
סעיף א
מערך המפתח: {1, 2, 1, 6, 1}
מה נדרש: לכל אות – בכמה מקומות היא זזה קדימה (מעגלית) מ־zebra ל־agcxb.
רעיון: מקום אות באלף־בית: a=0 , b=1 , … , z=25. ההזזה היא (מקום האות המוצפנת − מקום האות המקורית + 26) % 26.
| אינדקס | מקורית | מוצפנת | חישוב | הזזה |
|---|---|---|---|---|
| 0 | z (25) | a (0) | (0 − 25 + 26) % 26 | 1 |
| 1 | e (4) | g (6) | 6 − 4 | 2 |
| 2 | b (1) | c (2) | 2 − 1 | 1 |
| 3 | r (17) | x (23) | 23 − 17 | 6 |
| 4 | a (0) | b (1) | 1 − 0 | 1 |
פתרון – מערך המפתח:
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 1 | 2 | 1 | 6 | 1 |
בדיקה: בתוכנית הבדיקה חישבנו את המפתח מ־zebra ומ־agcxb וקיבלנו 1 2 1 6 1; ופענוח של agcxb עם המפתח הזה בפעולה מסעיף ב החזיר zebra.
טעות נפוצה: באות הראשונה לרשום −25 או 25 (ההפרש בלי מעגליות) – z זזה מקום אחד קדימה ונהיית a.
סעיף ב
לכל i: pos = (str.charAt(i) − 'a' − arr[i] + 26) % 26, ומשרשרים (char)('a' + pos).
מה נדרש: לפענח את המסר – להזיז כל אות אחורה מספר מקומות כערך התא המתאים במערך המפתח.
רעיון: ממירים כל אות למקומה באלף־בית: pos = str.charAt(i) - 'a' (0–25). מזיזים אחורה: pos - arr[i] – וזה יכול לצאת שלילי, לכן מוסיפים 26 ולוקחים שארית: (pos - arr[i] + 26) % 26. ממירים חזרה לתו: (char)('a' + pos) ומשרשרים לתוצאה.
פתרון: הקוד המלא – בלשונית Java/C#.
בדיקה:
decode("drdd", {1,3,0,25}) → code (הדוגמה שבשאלה; באות האחרונה: d=3 , (3 − 25 + 26) % 26 = 4 = e).decode("agcxb", {1,2,1,6,1}) → zebra (סעיף א).decode("a", {1}) → z; decode("abc", {0,0,0}) → abc.טעות נפוצה: לשכוח את ה־+ 26 – ב־Java וב־C# שארית של מספר שלילי היא שלילית (למשל -22 % 26 הוא -22), ומתקבל תו שאינו אות. או להזיז קדימה במקום אחורה.
public class Q6
{
public static String decode(String str, int[] arr)
{
String result = "";
for (int i = 0; i < str.length(); i++)
{
int pos = str.charAt(i) - 'a'; // מקום האות באלף־בית (0–25)
pos = (pos - arr[i] + 26) % 26; // הזזה אחורה, באופן מעגלי
result += (char)('a' + pos);
}
return result;
}
}טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | א | count = 4 (המספרים 47 , 1302 , 9 , 2318 – שבהם ספרת האחדות גדולה מספרת העשרות). |
| ב | למשל arr = {21, 30, 99, 54} (בכל מספר ספרת האחדות קטנה מספרת העשרות או שווה לה). | |
| ג | למשל arr = {12, 389, 1045, 67} (בכל מספר ספרת האחדות גדולה מספרת העשרות). | |
| 2 | - | half = arr.length / 2; במערך עזר: temp[2·i] = arr[i] ו-temp[2·i + 1] = arr[half + i] לכל i < half; בסוף מעתיקים את temp חזרה ל-arr. |
| 3 | - | לכל i משווים את strand1.charAt(i) ל־ strand2.charAt(i): שוות → זהה; A/T או C/G → משלים; אחרת → שונה. בדוגמה: 2, 3, 2 |
| 4 | א | diverName = name; dives = new Dive[num]; |
| ב | return dives.length >= 10 && totalMinutes() >= 600; | |
| ג | לכל i: אם club[i].isAdvanced() – מדפיסים club[i].getDiverName() ומגדילים מונה; בסוף מחזירים את המונה. | |
| 5 | א(1) | return min·60 + sec < other.getMin()·60 + other.getSec(); |
| א(2) | מחפשים את השיר הקצר ביותר (best) בעזרת isShorter ומדפיסים best.getArtist(). | |
| ב(1) | סכום getPlays() של כל השירים שבהם getArtist() == artist. | |
| ב(2) | מקסימום של totalPlays(arr, arr[i].getArtist()) על כל i; מחזירים את קוד האמן שבו התקבל. | |
| 6 | א | מערך המפתח: {1, 2, 1, 6, 1} |
| ב | לכל i: pos = (str.charAt(i) − 'a' − arr[i] + 26) % 26, ומשרשרים (char)('a' + pos). |