דילוג לתוכן המרכזי

מתכונת 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 , המכיל מספרים שלמים חיוביים.

0123456
arr471302859560231871

לפניכם קטע תוכנית, הכתוב בשפות Java ו־ C# .

Java

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#

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 נוספה לנוחות):

iarr[i]abswappedarr[i]%100swapped > arr[i]%100 ?count
0
047747447כן1
1130220202כן2
285585885לא2
3990909כן3
456006660לא3
52318818118כן4
671171771לא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 גדל רק כאשר ספרת האחדות גדולה מספרת העשרות. די לבחור מספרים שבהם ספרת האחדות קטנה או שווה לספרת העשרות.

פתרון: למשל

0123
arr21309954

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 – כלומר כל ארבעת המספרים נספרים.

רעיון: צריך שבכל מספר ספרת האחדות תהיה גדולה (ממש) מספרת העשרות. שאר הספרות (מאות, אלפים) אינן משפיעות.

פתרון: למשל

0123
arr12389104567
iarr[i]abswappedcount
01221211
138998982
2104554543
36776764

בדיקה: על {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 שלפניכם:

01234567
arr1138132951

המערך arr ייראה כך בסיום הפעולה:

01234567
arr1123985131

הסבר: החצי הראשון של המערך הוא 11, 3, 8, 13 והחצי השני הוא 2, 9, 5, 1. הפעולה שילבה את שני החצאים לסירוגין, החל באיבר הראשון של החצי הראשון.

ממשו את הפעולה shuffle בשפת Java או Shuffle בשפת C#, לפי התיאור שלמעלה.

(20 נקודות)
◂ פתרון מלא לשאלה 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

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#

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.

iarr[i] ← temp[2i]arr[half + i] ← temp[2i + 1]
011 ← temp[0]2 ← temp[1]
13 ← temp[2]9 ← temp[3]
28 ← temp[4]5 ← temp[5]
313 ← 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" :

אינדקס0123456
גדיל ראשוןACGTTAG
גדיל שניACCAAGT

שני ציוני "זהה" (באינדקסים 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):

•אם c1 == c2 – "זהה".
•אחרת, אם הזוג הוא A ו־ T או T ו־ A או C ו־ G או G ו־ C – "משלים".
•אחרת – "שונה".

את הבדיקה "זהה" עושים ראשונה; כך בבדיקת "משלים" כבר ידוע שהאותיות שונות.

פתרון: הקוד המלא – בלשונית Java / C#.

בדיקה:

strand1strand2פלט
ACGTTAGACCAAGT2, 3, 2 (כמו בדוגמה)
ACGTACGLength Error
ACGTACGT4, 0, 0
ACGTTGCA0, 4, 0
AACCCCAA0, 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 (שתיהן מספרים שלמים וחיוביים).

Java
public class Dive{
      private int depth;
      private int minutes;
}

בנוסף, נתונה המחלקה DiveLog המייצגת יומן צלילות של צולל ולה שתי תכונות: שם הצולל – diverName, ומערך של עצמים dives מטיפוס Dive בגודל מספר הצלילות שהצולל ביצע.

Java
public class DiveLog{
      private String diverName;
      private Dive[] dives;
}

הניחו שקיימות פעולות get ו־set בשפת Java ופעולות Get ו־Set בשפת C# בעבור כל התכונות בשתי המחלקות.

לפניכם ממשק חלקי של המחלקה DiveLog:

תיאור הפעולהכותרת הפעולה
פעולה בונה המקבלת את שם הצולל ואת מספר הצלילות שביצע, ומאתחלת את התכונות. המערך dives מאותחל למערך ריק בגודל numpublic 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
Liron12600true
Omer9720false
Shani10600true
Itay15585false
Gal20900true

טעות נפוצה: להשתמש ב־> במקום ב־>= ("לפחות" כולל את הגבול: 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 – שיר ברשימת ההשמעה של תחנת רדיו אזורית, ולה ארבע תכונות:

•artist – קוד האמן המבצע את השיר, מטיפוס שלם
•min – מספר הדקות השלמות באורך השיר, מטיפוס שלם
•sec – מספר השניות הנוספות באורך השיר (בין 0 ל־ 59), מטיפוס שלם
•plays – מספר הפעמים שהשיר הושמע בתחנה במהלך השבוע, מטיפוס שלם

לדוגמה, לשיר שאורכו 3:45 (שלוש דקות וארבעים וחמש שניות) יש min = 3 ו־ sec = 45 .

הניחו שהפעולות get/Get ו־ set/Set קיימות עבור תכונות המחלקה.
הערה: לאותו אמן (artist) יכולים להיות כמה שירים ברשימה.

נתון מערך שירים מלא – arr מטיפוס Track של רשימת ההשמעה השבועית. המערך אינו ממוין.

א.(1)

כתבו במחלקה Track פעולה פנימית ששמה isShorter בשפת Java או IsShorter בשפת C# , המקבלת שיר אחר – other (מטיפוס Track). הפעולה מחזירה true אם השיר הנוכחי קצר יותר מן השיר האחר (other), ואחרת מחזירה false .

(2)

כתבו פעולה חיצונית ששמה shortest בשפת Java או Shortest בשפת C# המקבלת את המערך arr , ומדפיסה את קוד האמן (artist) של השיר הקצר ביותר ברשימה.
הניחו שיש רק שיר אחד המקיים תנאי זה.
הערה: חובה להיעזר בפעולה שכתבתם בסעיף א(1).

ב.(1)

כתבו פעולה חיצונית ששמה totalPlays בשפת Java או TotalPlays בשפת C# המקבלת את המערך arr וקוד של אמן – artist . הפעולה מחזירה את מספר ההשמעות סך הכול של כל השירים של האמן artist ברשימה.
לדוגמה: אם לאמן artist יש ברשימה שני שירים, האחד הושמע 40 פעמים והשני 30 פעמים, יוחזר 70 .

(2)

כתבו פעולה חיצונית ששמה 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 .

0123
13025

הסבר: האות 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.

אינדקסמקוריתמוצפנתחישובהזזה
0z (25)a (0)(0 − 25 + 26) % 261
1e (4)g (6)6 − 42
2b (1)c (2)2 − 11
3r (17)x (23)23 − 176
4a (0)b (1)1 − 01

פתרון – מערך המפתח:

01234
12161

בדיקה: בתוכנית הבדיקה חישבנו את המפתח מ־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).

כל האתר במבט אחד

קיצורי דרך לכל הכלים, הבגרויות והקורסים

GuyAI הוא המורה הפרטי המתקדם בישראל, המבוסס על מודלי הבינה המלאכותית החזקים בעולם בשילוב הידע הפדגוגי של GOOL. המערכת מספקת פתרונות לכל המקצועות ולכל הרמות - מיסודי ועד אקדמיה, וממתמטיקה ועד היסטוריה.