בגרות במדעי המחשב יסודות מדעי המחשב 899371 - קיץ 2025
1–2 יח"ל · שאלון 899371 · 6 שאלות · 2:30 שעות · פתרון מלא לכל סעיף
בחינת הבגרות במדעי המחשב, יסודות מדעי המחשב, קיץ 2025, כל 6 השאלות כמו בשאלון. לכל סעיף יש תשובה ופתרון מלא: הרעיון, הקוד או המעקב, ובדיקה קצרה. כל קוד מופיע ב-Java וב-C#. נסו לפתור לבד, ואז פתחו את הפתרון.
הוראות הבחינה (כמו בשאלון)
א. משך הבחינה: שעתיים וחצי.
ב. מבנה השאלון ומפתח ההערכה: בשאלון זה שני פרקים.
פרק ראשון – (20×2) – 40 נקודות
פרק שני – (30×2) – 60 נקודות
סך הכול – 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנוּת.
ד. הוראה מיוחדת:
את כל התוכניות שיש לכתוב בשפת מחשב כתבו בשפה אחת בלבד – Java או C#.
הערה: לא יוּרדוּ נקודות אם תכתבו בתוכניות אות גדולה במקום אות קטנה או להפך.
יש לכתוב במחברת הבחינה בלבד. יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
השאלות
בשאלון זה שני פרקים.
יש לענות על שאלות משני הפרקים, לפי ההוראות בכל פרק.
הערה: בכל שאלה שנדרשת בה קליטה, אין צורך לבדוק את תקינות הקלט.
לפותרים בשפת Java: בכל שאלה שנדרשת בה קליטה, הניחו שבתוכנית כתובה ההוראה:
Scanner scan = new Scanner (System.in);
פרק ראשון (40 נקודות)
ענו על שתיים מן השאלות 1–3 (לכל שאלה – 20 נקודות).
שאלה 1 · מעקב אחר פעולה על מערך – הסכום הרציף הגדול ביותר (20 נקודות)
לפניכם הפעולה what בשפת Java או What בשפת C# :
Java
public static int what (int[] arr)
{
int y = 0;
int x = arr[0];
for (int i = 0; i < arr.length; i++)
{
y += arr[i];
x = Math.max (x, y);
y = Math.max (y, 0);
}
return x;
}C#
public static int What (int[] arr)
{
int y = 0;
int x = arr[0];
for (int i = 0 ;i < arr.Length; i++)
{
y += arr[i];
x = Math.Max (x, y);
y = Math.Max (y, 0);
}
return x;
}נתון המערך arr :
| 0 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| arr | 3 | 4 | -8 | 10 | -6 | 8 |
עקבו בעזרת טבלת מעקב אחר הפעולה what(arr) בשפת Java או What(arr) בשפת C#, וכתבו מה הפעולה מחזירה.
בטבלת המעקב יש לכלול עמודה בעבור כל אחד מן המשתנים האלה: i , y , x .
◂ פתרון מלא לשאלה 1
פתרון
הפעולה מחזירה 12 (הסכום הגדול ביותר של רצף איברים צמודים: 10 + (-6) + 8).
מה נדרש
לעקוב אחר ביצוע הפעולה על המערך {3, 4, -8, 10, -6, 8} בטבלת מעקב עם העמודות i, y, x, ולכתוב את הערך שהיא מחזירה.
רעיון
פתרון – טבלת מעקב
בכל שורה רשום ערכו של y אחרי y += arr[i], ערכו של x אחרי x = max(x, y) וערכו של y אחרי y = max(y, 0).
| שלב | i | arr[i] | y אחרי y += arr[i] | x | y אחרי y = max(y, 0) |
|---|---|---|---|---|---|
| אתחול | – | – | 0 | 3 | 0 |
| 1 | 0 | 3 | 3 | 3 | 3 |
| 2 | 1 | 4 | 7 | 7 | 7 |
| 3 | 2 | -8 | -1 | 7 | 0 |
| 4 | 3 | 10 | 10 | 10 | 10 |
| 5 | 4 | -6 | 4 | 10 | 4 |
| 6 | 5 | 8 | 12 | 12 | 12 |
| סיום | 6 | – | – | 12 | 12 |
כאשר i = 6 התנאי i < 6 אינו מתקיים, הלולאה מסתיימת והפעולה מחזירה את x.
הפעולה מחזירה 12.
(הסבר נוסף: הפעולה מחזירה את הסכום הגדול ביותר של רצף איברים צמודים במערך. כאן זה הרצף 10, -6, 8 שסכומו 12.)
בדיקה
על המערך הנתון מודפס 12. הדפסת ערכי המשתנים בכל סיבוב נתנה בדיוק את השורות שבטבלה.
טעות נפוצה: לשכוח שבשלב 3 קודם מעדכנים את x (שנשאר 7, כי y = -1 קטן ממנו) ורק אחר כך מאפסים את y. סדר שלוש ההוראות בלולאה חשוב.
שאלה 2 · סידור מערך – חיוביים לפני שליליים בשמירת הסדר (20 נקודות)
ממשו את הפעולה arrange בשפת Java או Arrange בשפת C# :
Java – public static void arrange (int[] arr)
C# – public static void Arrange (int[] arr)
במערך arr שמתקבל יש מספרים חיוביים ומספרים שליליים.
הפעולה מעבירה לתחילת המערך arr את כל המספרים החיוביים (כולל 0), וממקמת אחריהם את כל המספרים השליליים.
הסדר של המספרים החיוביים (בינם לבין עצמם) יישאר באותו הסדר שבו הם היו לפני הפעולה, וגם הסדר של המספרים השליליים (בינם לבין עצמם) יישאר באותו הסדר שבו הם היו לפני הפעולה.
דוגמה:
בעבור המערך arr שלפניכם:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|---|
| arr | 7 | -2 | -5 | 61 | 4 | -1 | 0 | 33 |
המערך arr ייראה כך בסיום הפעולה:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|---|
| arr | 7 | 61 | 4 | 0 | 33 | -2 | -5 | -1 |
הסבר: הפעולה העבירה לתחילת המערך את המספרים החיוביים, ושמרה על הסדר המקורי של המספרים החיוביים ושל המספרים השליליים.
ממשו את הפעולה arrange בשפת Java או Arrange בשפת C#, לפי התיאור שלמעלה.
◂ פתרון מלא לשאלה 2
פתרון
מעתיקים למערך עזר קודם את כל האיברים ≥ 0 לפי הסדר, אחריהם את כל השליליים לפי הסדר, ומעתיקים בחזרה ל-arr.
מה נדרש
לסדר מחדש את המערך arr כך שכל המספרים האי-שליליים (≥ 0) יהיו בהתחלה וכל השליליים אחריהם, בלי לשנות את הסדר הפנימי של כל קבוצה. הפעולה לא מחזירה ערך – היא משנה את arr עצמו.
רעיון
משתמשים במערך עזר temp באותו גודל ובמונה k (המקום הפנוי הבא ב-temp):
מכיוון שבכל מעבר סורקים את המערך לפי הסדר, הסדר היחסי בתוך כל קבוצה נשמר.
פתרון
Java
public static void arrange(int[] arr)
{
int[] temp = new int[arr.length];
int k = 0;
// שלב 1: מעתיקים את המספרים החיוביים (כולל 0) לפי הסדר
for (int i = 0; i < arr.length; i++)
{
if (arr[i] >= 0)
{
temp[k] = arr[i];
k++;
}
}
// שלב 2: מעתיקים אחריהם את המספרים השליליים לפי הסדר
for (int i = 0; i < arr.length; i++)
{
if (arr[i] < 0)
{
temp[k] = arr[i];
k++;
}
}
// שלב 3: מעתיקים את התוצאה בחזרה ל-arr
for (int i = 0; i < arr.length; i++)
{
arr[i] = temp[i];
}
}C#
public static void Arrange(int[] arr)
{
int[] temp = new int[arr.Length];
int k = 0;
// שלב 1: מעתיקים את המספרים החיוביים (כולל 0) לפי הסדר
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] >= 0)
{
temp[k] = arr[i];
k++;
}
}
// שלב 2: מעתיקים אחריהם את המספרים השליליים לפי הסדר
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] < 0)
{
temp[k] = arr[i];
k++;
}
}
// שלב 3: מעתיקים את התוצאה בחזרה ל-arr
for (int i = 0; i < arr.Length; i++)
{
arr[i] = temp[i];
}
}בדיקה
על מערך הדוגמה {7, -2, -5, 61, 4, -1, 0, 33}:
גם המקרים {-1, -2, 3} ← {3, -1, -2}, מערך בלי שליליים, מערך רק של שליליים ו-{0, -9, 0} ← {0, 0, -9} עובדים.
טעות נפוצה: להחליף (swap) איבר שלילי עם החיובי הבא אחריו "בקפיצה" – החלפה כזאת משבשת את הסדר של השליליים בינם לבין עצמם. טעות נוספת: לשכוח את שלב 3 – אם רק בונים מערך חדש ולא מעתיקים אותו חזרה ל-arr, המערך המקורי לא משתנה.
public static void arrange(int[] arr)
{
int[] temp = new int[arr.length];
int k = 0;
// שלב 1: מעתיקים את המספרים החיוביים (כולל 0) לפי הסדר
for (int i = 0; i < arr.length; i++)
{
if (arr[i] >= 0)
{
temp[k] = arr[i];
k++;
}
}
// שלב 2: מעתיקים אחריהם את המספרים השליליים לפי הסדר
for (int i = 0; i < arr.length; i++)
{
if (arr[i] < 0)
{
temp[k] = arr[i];
k++;
}
}
// שלב 3: מעתיקים את התוצאה בחזרה ל-arr
for (int i = 0; i < arr.length; i++)
{
arr[i] = temp[i];
}
}שאלה 3 · מספר נרקיסיסטי (20 נקודות)
מספר חיובי – num ייקרא "מספר נרקיסיסטי" אם מתקיים התנאי שלפניכם:
מעלים כל אחת מן הספרות של num בחזקת כמות הספרות שיש ב־ num (אורך המספר num),
מחברים את כל התוצאות, והסכום שמתקבל שווה ל־ num .
דוגמה ל"מספר נרקיסיסטי": המספר 407 , כי כאשר מעלים כל אחת מן הספרות שלו בחזקת 3 (שהיא כמות הספרות במספר) מקבלים 407 : 4³ + 0³ + 7³ = 64 + 0 + 343 = 407
דוגמה למספר שאינו "מספר נרקיסיסטי": המספר 58 , כי כאשר מעלים כל אחת מן הספרות שלו בחזקת 2 (שהיא כמות הספרות במספר) מקבלים 89 : 5² + 8² = 25 + 64 = 89 .
כתבו פעולה חיצונית ששמה isNarc בשפת Java או IsNarc בשפת C#, המקבלת מספר מטיפוס שלם – num הגדול מ־ 0 . הפעולה מחזירה true אם המספר נרקיסיסטי, אחרת היא מחזירה false .
כתבו פעולה חיצונית ששמה theNarc בשפת Java או TheNarc בשפת C#, המקבלת מספר מטיפוס שלם – n הגדול מ־ 0 . הפעולה מדפיסה את כל המספרים הנרקיסיסטיים שיש מ־ 1 ועד n (כולל).
הערה: יש להשתמש בפעולה שכתבתם בסעיף א.
◂ פתרון מלא לשאלה 3
סעיף א
סופרים ספרות (len), מחברים כל ספרה בחזקת len, ומחזירים sum == num.
מה נדרש
פעולה בוליאנית שבודקת אם num שווה לסכום ספרותיו, כשכל ספרה מועלית בחזקת מספר הספרות של num.
רעיון
שני מעברים על הספרות (בעזרת % 10 ו-/ 10), תמיד על עותק temp כדי לא להרוס את num:
בסוף משווים את הסכום ל-num.
(אפשר גם להשתמש ב-Math.pow / Math.Pow, אבל היא מחזירה double ולכן צריך המרה ל-int; כפל בלולאה פשוט ובטוח יותר.)
פתרון
Java
public static boolean isNarc(int num)
{
// שלב 1: סופרים כמה ספרות יש ב-num
int len = 0;
int temp = num;
while (temp > 0)
{
len++;
temp = temp / 10;
}
// שלב 2: מחברים כל ספרה בחזקת len
int sum = 0;
temp = num;
while (temp > 0)
{
int digit = temp % 10;
int power = 1;
for (int i = 1; i <= len; i++)
{
power = power * digit;
}
sum = sum + power;
temp = temp / 10;
}
return sum == num;
}C#
public static bool IsNarc(int num)
{
// שלב 1: סופרים כמה ספרות יש ב-num
int len = 0;
int temp = num;
while (temp > 0)
{
len++;
temp = temp / 10;
}
// שלב 2: מחברים כל ספרה בחזקת len
int sum = 0;
temp = num;
while (temp > 0)
{
int digit = temp % 10;
int power = 1;
for (int i = 1; i <= len; i++)
{
power = power * digit;
}
sum = sum + power;
temp = temp / 10;
}
return sum == num;
}בדיקה
isNarc(407) = true, isNarc(58) = false, isNarc(153) = true, isNarc(9474) = true, isNarc(9475) = false.
טעות נפוצה: לספור את הספרות על num עצמו (num = num / 10) – בסוף num כבר 0 ואין עם מה להשוות. תמיד עובדים על עותק.
public static boolean isNarc(int num)
{
// שלב 1: סופרים כמה ספרות יש ב-num
int len = 0;
int temp = num;
while (temp > 0)
{
len++;
temp = temp / 10;
}
// שלב 2: מחברים כל ספרה בחזקת len
int sum = 0;
temp = num;
while (temp > 0)
{
int digit = temp % 10;
int power = 1;
for (int i = 1; i <= len; i++)
{
power = power * digit;
}
sum = sum + power;
temp = temp / 10;
}
return sum == num;
}סעיף ב
לולאה i = 1..n, מדפיסים i אם isNarc(i). למשל עד 10000: 1–9, 153, 370, 371, 407, 1634, 8208, 9474.
מה נדרש
להדפיס את כל המספרים הנרקיסיסטיים מ-1 עד n, תוך שימוש ב-isNarc מסעיף א.
רעיון
לולאה על i מ-1 עד n (כולל); לכל i קוראים ל-isNarc(i), ואם התשובה true – מדפיסים את i.
פתרון
Java
public static void theNarc(int n)
{
for (int i = 1; i <= n; i++)
{
if (isNarc(i))
{
System.out.println(i);
}
}
}C#
public static void TheNarc(int n)
{
for (int i = 1; i <= n; i++)
{
if (IsNarc(i))
{
Console.WriteLine(i);
}
}
}בדיקה
שימו לב: כל מספר חד-ספרתי הוא נרקיסיסטי (למשל 5¹ = 5), ולכן ההדפסה תמיד מתחילה ב-1.
theNarc(10000) מדפיסה:
1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474
(כל מספר בשורה נפרדת). התוצאה זהה לבדיקה עצמאית שכתבנו בנפרד.
public static void theNarc(int n)
{
for (int i = 1; i <= n; i++)
{
if (isNarc(i))
{
System.out.println(i);
}
}
}פרק שני (60 נקודות)
ענו על שתיים מן השאלות 4–6 (לכל שאלה – 30 נקודות).
שאלה 4 · מחלקת הסעות – Transport ומערך של הסעות (30 נקודות)
למועצה האזורית "עוז" משתייכים כמה יישובים. המועצה מספקת לילדים הגרים ביישובים אלה שירותי הסעה מן הבית אל בית הספר ובחזרה. הסעה מן הבית אל בית הספר נקראת "הסעה הלוך" והסעה בחזרה מבית הספר אל הבית נקראת "הסעה חזור".
נתונה המחלקה Transport – הסעה, ולה ארבע תכונות:
הניחו שקיימות פעולות get/Get לתכונות המחלקה.
כתבו פעולה בונה במחלקה Transport , המקבלת את שם היישוב שבעבורו ההסעה – name , מספר התלמידים בהסעה – num , והיום בשבוע שבו ההסעה מתבצעת – day .
הפעולה תאתחל את תכונות המחלקה. בסוג ההסעה (toSchool) הפעולה תיצור "הסעה הלוך".
הניחו שהפרמטרים שמתקבלים תקינים.
כתבו פעולה בונה במחלקה Transport המקבלת רק את מספר התלמידים בהסעה – num .
הפעולה תאתחל את תכונות המחלקה כך שתתקבל "הסעה חזור" ביישוב Aviv ביום רביעי עם num תלמידים.
הערה: אם פרמטר מספר התלמידים (num) אינו תקין, התכונה תקבל 1 .
נתון מערך – arr , מטיפוס Transport , המכיל את ההסעות שהתבצעו במהלך השבוע. המערך אינו ממוין לפי סדר כלשהו, ואין בו ערכי null .
כתבו פעולה חיצונית ששמה dayReport בשפת Java או DayReport בשפת C#, המקבלת את המערך arr , מספר מטיפוס שלם – day המציין יום בשבוע, ופרמטר בוליאני – forward .
אם forward הוא true , הפעולה תחזיר את סך מספר התלמידים שנסעו ב"הסעות הלוך" ביום – day .
אחרת (אם forward הוא false ), הפעולה תחזיר את סך מספר התלמידים שנסעו ב"הסעות חזור" ביום – day .
הניחו שהפרמטר day שמתקבל תקין (בין 1 ל־ 6 ).
כתבו פעולה חיצונית ששמה moreForward בשפת Java או MoreForward בשפת C#, המקבלת את המערך arr .
הפעולה תדפיס את מספרי הימים בשבוע שבהם מספר התלמידים שנסעו ב"הסעות הלוך" היה גדול יותר ממספר התלמידים שנסעו ב"הסעות חזור".
הערה: אפשר להיעזר בפעולה שכתבתם בתת־סעיף ב(1).
◂ פתרון מלא לשאלה 4
סעיף א(1)
this.name = name; this.num = num; this.day = day; this.toSchool = true;
מה נדרש
פעולה בונה עם שלושה פרמטרים (name, num, day) שמאתחלת את ארבע התכונות; toSchool מקבלת תמיד true ("הסעה הלוך").
רעיון
מציבים כל פרמטר בתכונה המתאימה (this.name = name וכו'). התכונה toSchool אינה פרמטר – מציבים בה true. אין צורך לבדוק תקינות (נאמר שהפרמטרים תקינים).
פתרון
התכונות של המחלקה (כותרת המחלקה):
Java
public class Transport
{
private String name; // שם היישוב
private boolean toSchool; // true = הסעה הלוך, false = הסעה חזור
private int num; // מספר התלמידים (1–50)
private int day; // יום בשבוע (1–6)C#
public class Transport
{
private string name; // שם היישוב
private bool toSchool; // true = הסעה הלוך, false = הסעה חזור
private int num; // מספר התלמידים (1–50)
private int day; // יום בשבוע (1–6)הפעולה הבונה:
Java
// סעיף א(1)
public Transport(String name, int num, int day)
{
this.name = name;
this.num = num;
this.day = day;
this.toSchool = true; // "הסעה הלוך"
}C#
// סעיף א(1)
public Transport(string name, int num, int day)
{
this.name = name;
this.num = num;
this.day = day;
this.toSchool = true; // "הסעה הלוך"
}המחלקה המלאה (עם שתי הפעולות הבונות ופעולות ה-get) – בלשונית הקוד של סעיף א(2).
בדיקה
new Transport("Oz", 30, 2) ← name = "Oz", toSchool = true, num = 30, day = 2.
// סעיף א(1)
public Transport(String name, int num, int day)
{
this.name = name;
this.num = num;
this.day = day;
this.toSchool = true; // "הסעה הלוך"
}סעיף א(2)
name = "Aviv", toSchool = false, day = 4, num = (1 ≤ num ≤ 50 ? num : 1).
מה נדרש
פעולה בונה נוספת עם פרמטר אחד (num) שיוצרת "הסעה חזור" ביישוב Aviv ביום רביעי.
רעיון
פתרון
Java
// סעיף א(2)
public Transport(int num)
{
this.name = "Aviv";
this.toSchool = false; // "הסעה חזור"
this.day = 4; // יום רביעי
if (num >= 1 && num <= 50)
this.num = num;
else
this.num = 1;
}C#
// סעיף א(2)
public Transport(int num)
{
this.name = "Aviv";
this.toSchool = false; // "הסעה חזור"
this.day = 4; // יום רביעי
if (num >= 1 && num <= 50)
this.num = num;
else
this.num = 1;
}המחלקה המלאה כפי שהודרה ונבדקה:
Java
public class Transport
{
private String name; // שם היישוב
private boolean toSchool; // true = הסעה הלוך, false = הסעה חזור
private int num; // מספר התלמידים (1–50)
private int day; // יום בשבוע (1–6)
// סעיף א(1)
public Transport(String name, int num, int day)
{
this.name = name;
this.num = num;
this.day = day;
this.toSchool = true; // "הסעה הלוך"
}
// סעיף א(2)
public Transport(int num)
{
this.name = "Aviv";
this.toSchool = false; // "הסעה חזור"
this.day = 4; // יום רביעי
if (num >= 1 && num <= 50)
this.num = num;
else
this.num = 1;
}
public String getName() { return this.name; }
public boolean getToSchool() { return this.toSchool; }
public int getNum() { return this.num; }
public int getDay() { return this.day; }
}C#
public class Transport
{
private string name; // שם היישוב
private bool toSchool; // true = הסעה הלוך, false = הסעה חזור
private int num; // מספר התלמידים (1–50)
private int day; // יום בשבוע (1–6)
// סעיף א(1)
public Transport(string name, int num, int day)
{
this.name = name;
this.num = num;
this.day = day;
this.toSchool = true; // "הסעה הלוך"
}
// סעיף א(2)
public Transport(int num)
{
this.name = "Aviv";
this.toSchool = false; // "הסעה חזור"
this.day = 4; // יום רביעי
if (num >= 1 && num <= 50)
this.num = num;
else
this.num = 1;
}
public string GetName() { return this.name; }
public bool GetToSchool() { return this.toSchool; }
public int GetNum() { return this.num; }
public int GetDay() { return this.day; }
}בדיקה
טעות נפוצה: לכתוב day = 3 ליום רביעי (הימים ממוספרים מ-1 = ראשון, ולכן רביעי = 4), או לבדוק רק num > 50 ולשכוח ש-0 ומספרים שליליים גם אינם תקינים.
public class Transport
{
private String name; // שם היישוב
private boolean toSchool; // true = הסעה הלוך, false = הסעה חזור
private int num; // מספר התלמידים (1–50)
private int day; // יום בשבוע (1–6)
// סעיף א(1)
public Transport(String name, int num, int day)
{
this.name = name;
this.num = num;
this.day = day;
this.toSchool = true; // "הסעה הלוך"
}
// סעיף א(2)
public Transport(int num)
{
this.name = "Aviv";
this.toSchool = false; // "הסעה חזור"
this.day = 4; // יום רביעי
if (num >= 1 && num <= 50)
this.num = num;
else
this.num = 1;
}
public String getName() { return this.name; }
public boolean getToSchool() { return this.toSchool; }
public int getNum() { return this.num; }
public int getDay() { return this.day; }
}סעיף ב(1)
סוכמים getNum() של כל הסעה שבה getDay() == day וגם getToSchool() == forward.
מה נדרש
לסכם את מספר התלמידים בכל ההסעות שבהן היום הוא day וסוג ההסעה מתאים ל-forward.
רעיון
סריקה של כל המערך עם צובר sum. הסעה נספרת אם getDay() == day וגם getToSchool() == forward. ההשוואה getToSchool() == forward מטפלת בשני המקרים יחד: כש-forward הוא true נספרות הסעות הלוך, וכשהוא false – הסעות חזור.
פתרון
Java
// סעיף ב(1)
public static int dayReport(Transport[] arr, int day, boolean forward)
{
int sum = 0;
for (int i = 0; i < arr.length; i++)
{
if (arr[i].getDay() == day && arr[i].getToSchool() == forward)
{
sum = sum + arr[i].getNum();
}
}
return sum;
}C#
// סעיף ב(1)
public static int DayReport(Transport[] arr, int day, bool forward)
{
int sum = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i].GetDay() == day && arr[i].GetToSchool() == forward)
{
sum = sum + arr[i].GetNum();
}
}
return sum;
}בדיקה
מערך בדיקה: ("Oz",30,1), ("Tal",10,1), Transport(25), ("Oz",20,4), ("Gil",40,2), Transport(15), ("Tal",5,4), ("Gil",12,6).
(ההסעות שנבנו בפעולה הבונה השנייה הן "הסעות חזור" ביום 4.)
// סעיף ב(1)
public static int dayReport(Transport[] arr, int day, boolean forward)
{
int sum = 0;
for (int i = 0; i < arr.length; i++)
{
if (arr[i].getDay() == day && arr[i].getToSchool() == forward)
{
sum = sum + arr[i].getNum();
}
}
return sum;
}סעיף ב(2)
לכל day מ-1 עד 6: אם dayReport(arr, day, true) > dayReport(arr, day, false) – מדפיסים day.
מה נדרש
להדפיס כל יום (1 עד 6) שבו סך התלמידים בהסעות הלוך גדול מסך התלמידים בהסעות חזור.
רעיון
לולאה על day מ-1 עד 6. לכל יום קוראים פעמיים ל-dayReport (מסעיף ב(1)): פעם עם true ופעם עם false, ומשווים. אם הלוך > חזור – מדפיסים את day.
פתרון
Java
// סעיף ב(2)
public static void moreForward(Transport[] arr)
{
for (int day = 1; day <= 6; day++)
{
if (dayReport(arr, day, true) > dayReport(arr, day, false))
{
System.out.println(day);
}
}
}C#
// סעיף ב(2)
public static void MoreForward(Transport[] arr)
{
for (int day = 1; day <= 6; day++)
{
if (DayReport(arr, day, true) > DayReport(arr, day, false))
{
Console.WriteLine(day);
}
}
}בדיקה
על מערך הבדיקה מסעיף ב(1):
| יום | הלוך | חזור | מודפס? |
|---|---|---|---|
| 1 | 40 | 0 | כן |
| 2 | 40 | 0 | כן |
| 3 | 0 | 0 | לא (לא גדול) |
| 4 | 25 | 40 | לא |
| 5 | 0 | 0 | לא |
| 6 | 12 | 0 | כן |
מודפסים 1, 2, 6.
טעות נפוצה: להשתמש ב-≥ במקום ב-> – אז יודפסו גם ימים שבהם המספרים שווים (למשל יום שאין בו הסעות בכלל).
// סעיף ב(2)
public static void moreForward(Transport[] arr)
{
for (int day = 1; day <= 6; day++)
{
if (dayReport(arr, day, true) > dayReport(arr, day, false))
{
System.out.println(day);
}
}
}שאלה 5 · רשת חברתית – חברים משותפים (30 נקודות)
נתונה המחלקה User – משתמש ברשת חברתית, ולה שלוש תכונות:
הניחו שקיימות פעולות get/Get לתכונות המחלקה.
כתבו במחלקה User פעולה פנימית ששמה mutual בשפת Java או Mutual בשפת C#, המקבלת משתמש (User) אחר – other . הפעולה מחזירה את כמות החברים המשותפים של שני המשתמשים.
נתונה המחלקה SocialNetwork – רשת חברתית, ולה תכונה אחת:
המערך אינו ממוין לפי סדר כלשהו, כל משתמש מופיע בו פעם אחת בלבד, ואין בו ערכי null .
כתבו במחלקה SocialNetwork פעולה פנימית ששמה exactOne בשפת Java או ExactOne בשפת C#, המקבלת משתמש (User) – other , שאינו מופיע במערך. הפעולה מחזירה true אם קיים במערך משתמש אחד לפחות שלו ול־ other יש בדיוק חבר אחד משותף. אחרת הפעולה מחזירה false .
הערה: אפשר להיעזר בפעולה שכתבתם בסעיף א.
◂ פתרון מלא לשאלה 5
סעיף א
שתי לולאות מקוננות על this.friends ו-other.getFriends(), סופרים התאמות.
מה נדרש
פעולה פנימית (פעולה של עצם) במחלקה User שסופרת כמה מספרי זהות מופיעים גם במערך friends של העצם הנוכחי (this) וגם במערך החברים של other.
רעיון
שתי לולאות מקוננות: לכל חבר של this עוברים על כל החברים של other; כשנמצא אותו מספר זהות – מגדילים מונה. מכיוון שבכל מערך כל מספר מופיע פעם אחת בלבד, כל חבר משותף נספר בדיוק פעם אחת.
בתוך המחלקה ניגשים ישירות ל-this.friends; את המערך של other מקבלים בעזרת other.getFriends() (בתוך אותה מחלקה מותר גם other.friends).
פתרון
הפעולה הבונה ופעולות ה-get אינן חלק מהתשובה (הן נתונות בשאלה); כתבנו אותן כדי שנוכל להריץ ולבדוק.
Java
public class User
{
private String name;
private int id;
private int[] friends;
// פעולה בונה ופעולות get – נתונות בשאלה (נכתבו כאן לצורך הבדיקה)
public User(String name, int id, int[] friends)
{
this.name = name;
this.id = id;
this.friends = friends;
}
public String getName() { return this.name; }
public int getId() { return this.id; }
public int[] getFriends() { return this.friends; }
// סעיף א
public int mutual(User other)
{
int[] otherFriends = other.getFriends();
int count = 0;
for (int i = 0; i < this.friends.length; i++)
{
for (int j = 0; j < otherFriends.length; j++)
{
if (this.friends[i] == otherFriends[j])
{
count++;
}
}
}
return count;
}
}C#
public class User
{
private string name;
private int id;
private int[] friends;
// פעולה בונה ופעולות Get – נתונות בשאלה (נכתבו כאן לצורך הבדיקה)
public User(string name, int id, int[] friends)
{
this.name = name;
this.id = id;
this.friends = friends;
}
public string GetName() { return this.name; }
public int GetId() { return this.id; }
public int[] GetFriends() { return this.friends; }
// סעיף א
public int Mutual(User other)
{
int[] otherFriends = other.GetFriends();
int count = 0;
for (int i = 0; i < this.friends.Length; i++)
{
for (int j = 0; j < otherFriends.Length; j++)
{
if (this.friends[i] == otherFriends[j])
{
count++;
}
}
}
return count;
}
}בדיקה
a.friends = {2, 3, 4, 5}, b.friends = {1, 3, 5, 9} ← המשותפים: 3 ו-5 ← a.mutual(b) = 2 (וגם b.mutual(a) = 2).
c.friends = {1, 2} ← a.mutual(c) = 1 (רק 2). משתמש בלי חברים ← 0.
public class User
{
private String name;
private int id;
private int[] friends;
// פעולה בונה ופעולות get – נתונות בשאלה (נכתבו כאן לצורך הבדיקה)
public User(String name, int id, int[] friends)
{
this.name = name;
this.id = id;
this.friends = friends;
}
public String getName() { return this.name; }
public int getId() { return this.id; }
public int[] getFriends() { return this.friends; }
// סעיף א
public int mutual(User other)
{
int[] otherFriends = other.getFriends();
int count = 0;
for (int i = 0; i < this.friends.length; i++)
{
for (int j = 0; j < otherFriends.length; j++)
{
if (this.friends[i] == otherFriends[j])
{
count++;
}
}
}
return count;
}
}סעיף ב
עוברים על users; אם users[i].mutual(other) == 1 מחזירים true; בסוף הלולאה מחזירים false.
מה נדרש
פעולה פנימית ב-SocialNetwork (מחלקה שמכילה מערך של עצמים מטיפוס User) שבודקת אם יש במערך users משתמש אחד לפחות שמספר החברים המשותפים שלו עם other הוא בדיוק 1.
רעיון
חיפוש סדרתי: עוברים על users; לכל משתמש קוראים ל-users[i].mutual(other) (מסעיף א). ברגע שמתקבל 1 – מחזירים true מיד. אם הלולאה הסתיימה בלי למצוא – מחזירים false.
פתרון
(הפעולה הבונה נכתבה לצורך הבדיקה בלבד.)
Java
public class SocialNetwork
{
private User[] users;
// פעולה בונה – לצורך הבדיקה
public SocialNetwork(User[] users)
{
this.users = users;
}
// סעיף ב
public boolean exactOne(User other)
{
for (int i = 0; i < this.users.length; i++)
{
if (this.users[i].mutual(other) == 1)
{
return true;
}
}
return false;
}
}C#
public class SocialNetwork
{
private User[] users;
// פעולה בונה – לצורך הבדיקה
public SocialNetwork(User[] users)
{
this.users = users;
}
// סעיף ב
public bool ExactOne(User other)
{
for (int i = 0; i < this.users.Length; i++)
{
if (this.users[i].Mutual(other) == 1)
{
return true;
}
}
return false;
}
}בדיקה
ברשת עם המשתמשים a = {2, 3, 4, 5} ו-b = {1, 3, 5, 9}:
טעות נפוצה: לכתוב בתוך הלולאה else return false – אז הפעולה בודקת רק את המשתמש הראשון. את false מחזירים רק אחרי שהלולאה עברה על כל המערך.
public class SocialNetwork
{
private User[] users;
// פעולה בונה – לצורך הבדיקה
public SocialNetwork(User[] users)
{
this.users = users;
}
// סעיף ב
public boolean exactOne(User other)
{
for (int i = 0; i < this.users.length; i++)
{
if (this.users[i].mutual(other) == 1)
{
return true;
}
}
return false;
}
}שאלה 6 · מספרים מושלמים (30 נקודות)
מספר חיובי – num ייקרא "מספר מושלם" אם מתקיים התנאי שלפניכם:
מחברים את כל המחלקים החיוביים והשלמים של num (המספרים שאם מחלקים את num בהם מקבלים תוצאה ללא שארית), חוץ ממנו, והסכום שמתקבל שווה למספר המקורי.
דוגמה למספר מושלם: המספר 6 , כי המחלקים שלו הם: 1 , 2 , 3 , והסכום שלהם הוא 6 .
דוגמה נוספת למספר מושלם: המספר 28 , כי המחלקים שלו הם: 1 , 2 , 4 , 7 , 14 , והסכום שלהם הוא 28 .
דוגמה למספר שאינו מספר מושלם: המספר 8 , כי המחלקים שלו הם: 1 , 2 , 4 , והסכום שלהם הוא 7 .
כתבו פעולה חיצונית ששמה isPerfect בשפת Java או IsPerfect בשפת C#, המקבלת מספר שלם – num הגדול מ־ 2 . הפעולה מחזירה true אם הוא מספר מושלם, אחרת היא מחזירה false .
כתבו פעולה חיצונית ששמה thePerfects בשפת Java או ThePerfects בשפת C#, המקבלת שני מספרים שלמים הגדולים מ־ 2 : low , high . הפעולה תדפיס את כל המספרים המושלמים שבין שני מספרים אלה (כולל).
הניחו ש־ low קטן מ־ high או שווה לו.
הערה: אפשר להיעזר בפעולה שכתבתם בתת־סעיף (1).
דוגמה: בעבור low=4 ו־ high=10 הפעולה תדפיס 6 .
הסבר: מן המספר 4 ועד 10 , רק המספר 6 הוא מספר מושלם (המספר 4 אינו מספר מושלם כי סכום המחלקים שלו: 1 , 2 , הוא 3 , המספר 5 אינו מספר מושלם כי רק המספר 1 מחלק אותו, וכן הלאה).
יש השערה שלא קיים מספר אי־זוגי שהוא מספר מושלם.
כתבו פעולה חיצונית ששמה noOdd בשפת Java או NoOdd בשפת C#, המחזירה true אם אכן מבין כל המספרים 3 עד 999,999 (כולל) אין מספר מושלם שהוא אי־זוגי. אחרת היא מחזירה false .
הערה: אפשר להיעזר בפעולה שכתבתם בתת־סעיף א(1).
◂ פתרון מלא לשאלה 6
סעיף א(1)
סכום כל המחלקים של num שקטנים ממנו, והשוואה ל-num.
מה נדרש
לבדוק אם סכום המחלקים של num (חוץ מ-num עצמו) שווה ל-num.
רעיון
הדרך הפשוטה: לעבור על כל i מ-1 עד num / 2 (מחלק של num שאינו num עצמו לא יכול להיות גדול מ-num / 2), ולחבר כל i שמחלק את num בלי שארית.
הדרך המהירה (זו שבקוד הראשי): מחלקים באים בזוגות – אם i מחלק את num, גם num / i מחלק אותו. לכן מספיק לעבור על i מ-2 כל עוד i * i ≤ num, ולכל מחלק i להוסיף גם את i וגם את num / i (פעם אחת בלבד אם הם שווים, למשל 3 ו-3 ב-9). את 1 מוסיפים מראש; את num עצמו (בן-הזוג של 1) לא מוסיפים.
למשל ל-28: i = 2 ← מוסיפים 2 ו-14; i = 4 ← מוסיפים 4 ו-7; 1 + 2 + 14 + 4 + 7 = 28.
פתרון
Java
public static boolean isPerfect(int num)
{
int sum = 1; // 1 מחלק כל מספר (ו-num > 2, לכן 1 שונה מ-num)
for (int i = 2; i * i <= num; i++)
{
if (num % i == 0)
{
sum = sum + i; // המחלק הקטן
int other = num / i; // המחלק ה"בן-זוג"
if (other != i)
{
sum = sum + other;
}
}
}
return sum == num;
}C#
public static bool IsPerfect(int num)
{
int sum = 1; // 1 מחלק כל מספר (ו-num > 2, לכן 1 שונה מ-num)
for (int i = 2; i * i <= num; i++)
{
if (num % i == 0)
{
sum = sum + i; // המחלק הקטן
int other = num / i; // המחלק ה"בן-זוג"
if (other != i)
{
sum = sum + other;
}
}
}
return sum == num;
}גם הגרסה הפשוטה נכונה (בדקנו ששתי הגרסאות נותנות אותה תשובה לכל המספרים 3 עד 20,000):
Java
public static boolean isPerfectSimple(int num)
{
int sum = 0;
for (int i = 1; i <= num / 2; i++)
{
if (num % i == 0)
{
sum = sum + i;
}
}
return sum == num;
}C#
public static bool IsPerfectSimple(int num)
{
int sum = 0;
for (int i = 1; i <= num / 2; i++)
{
if (num % i == 0)
{
sum = sum + i;
}
}
return sum == num;
}בדיקה
isPerfect(6) = true, isPerfect(28) = true, isPerfect(496) = true, isPerfect(8) = false (1 + 2 + 4 = 7), isPerfect(4) = false, isPerfect(9) = false (1 + 3 = 4).
טעות נפוצה: בגרסה המהירה – להוסיף פעמיים את השורש כשהמספר הוא ריבוע (ב-9: 3 ו-9/3 = 3), או לכלול את num עצמו בסכום.
public static boolean isPerfect(int num)
{
int sum = 1; // 1 מחלק כל מספר (ו-num > 2, לכן 1 שונה מ-num)
for (int i = 2; i * i <= num; i++)
{
if (num % i == 0)
{
sum = sum + i; // המחלק הקטן
int other = num / i; // המחלק ה"בן-זוג"
if (other != i)
{
sum = sum + other;
}
}
}
return sum == num;
}סעיף א(2)
לולאה i = low..high, מדפיסים i אם isPerfect(i). למשל low=4, high=10 ← 6.
מה נדרש
להדפיס את כל המספרים המושלמים בטווח low עד high (כולל), בעזרת isPerfect.
רעיון
לולאה על i מ-low עד high (כולל); אם isPerfect(i) מחזירה true – מדפיסים את i. מותר לקרוא ל-isPerfect כי כל i בטווח גדול מ-2.
פתרון
Java
public static void thePerfects(int low, int high)
{
for (int i = low; i <= high; i++)
{
if (isPerfect(i))
{
System.out.println(i);
}
}
}C#
public static void ThePerfects(int low, int high)
{
for (int i = low; i <= high; i++)
{
if (IsPerfect(i))
{
Console.WriteLine(i);
}
}
}בדיקה
public static void thePerfects(int low, int high)
{
for (int i = low; i <= high; i++)
{
if (isPerfect(i))
{
System.out.println(i);
}
}
}סעיף ב
לולאה על האי-זוגיים 3, 5, ..., 999999; אם isPerfect(i) – מחזירים false; בסוף מחזירים true. (התוצאה: true.)
מה נדרש
פעולה בלי פרמטרים שבודקת את כל המספרים האי-זוגיים מ-3 עד 999,999: אם אחד מהם מושלם – מחזירה false; אם אף אחד אינו מושלם – מחזירה true.
רעיון
חיפוש סדרתי על המספרים האי-זוגיים בלבד: מתחילים ב-3 ומקדמים ב-2 (3, 5, 7, ..., 999,999). אם isPerfect(i) מחזירה true – מצאנו מספר מושלם אי-זוגי ומחזירים false מיד. אם הלולאה הסתיימה – מחזירים true.
(999,999 אי-זוגי, ולכן הלולאה i ≤ 999999 עם קפיצות של 2 מגיעה אליו בדיוק.)
פתרון
Java
public static boolean noOdd()
{
for (int i = 3; i <= 999999; i = i + 2)
{
if (isPerfect(i))
{
return false;
}
}
return true;
}C#
public static bool NoOdd()
{
for (int i = 3; i <= 999999; i = i + 2)
{
if (IsPerfect(i))
{
return false;
}
}
return true;
}בדיקה
הפעולה מחזירה true – אין מספר מושלם אי-זוגי בין 3 ל-999,999 (והגרסה המהירה של isPerfect מסעיף א(1) מסיימת את הבדיקה מהר).
הערה: עם הגרסה הפשוטה של isPerfect (לולאה עד num / 2) הפעולה נכונה באותה מידה, אבל היא מבצעת כ-10¹¹ פעולות חלוקה ולכן רצה זמן רב מאוד. השאלה לא דורשת יעילות, אבל כדאי להכיר את הרעיון של מחלקים בזוגות.
טעות נפוצה: להחזיר true בתוך הלולאה (למשל ב-else) כבר אחרי המספר הראשון שאינו מושלם – אפשר להחזיר true רק אחרי שבדקנו את כל המספרים.
public static boolean noOdd()
{
for (int i = 3; i <= 999999; i = i + 2)
{
if (isPerfect(i))
{
return false;
}
}
return true;
}טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | הפעולה מחזירה 12 (הסכום הגדול ביותר של רצף איברים צמודים: 10 + (-6) + 8). |
| 2 | - | מעתיקים למערך עזר קודם את כל האיברים ≥ 0 לפי הסדר, אחריהם את כל השליליים לפי הסדר, ומעתיקים בחזרה ל-arr. |
| 3 | א | סופרים ספרות (len), מחברים כל ספרה בחזקת len, ומחזירים sum == num. |
| ב | לולאה i = 1..n, מדפיסים i אם isNarc(i). למשל עד 10000: 1–9, 153, 370, 371, 407, 1634, 8208, 9474. | |
| 4 | א(1) | this.name = name; this.num = num; this.day = day; this.toSchool = true; |
| א(2) | name = "Aviv", toSchool = false, day = 4, num = (1 ≤ num ≤ 50 ? num : 1). | |
| ב(1) | סוכמים getNum() של כל הסעה שבה getDay() == day וגם getToSchool() == forward. | |
| ב(2) | לכל day מ-1 עד 6: אם dayReport(arr, day, true) > dayReport(arr, day, false) – מדפיסים day. | |
| 5 | א | שתי לולאות מקוננות על this.friends ו-other.getFriends(), סופרים התאמות. |
| ב | עוברים על users; אם users[i].mutual(other) == 1 מחזירים true; בסוף הלולאה מחזירים false. | |
| 6 | א(1) | סכום כל המחלקים של num שקטנים ממנו, והשוואה ל-num. |
| א(2) | לולאה i = low..high, מדפיסים i אם isPerfect(i). למשל low=4, high=10 ← 6. | |
| ב | לולאה על האי-זוגיים 3, 5, ..., 999999; אם isPerfect(i) – מחזירים false; בסוף מחזירים true. (התוצאה: true.) |