→ חזרו אחורה

פרק 11 - צמתים מקושרים (Node)

⏱ 12 דקות קריאה

עד עכשיו כל המבנים שלנו היו מערכים - גודל קבוע שנקבע מראש. הפרק הזה פותח יחידה חדשה: מבני נתונים שבונים "שרשרת" מקושרת של איברים, שיכולה לגדול איבר אחד בכל פעם. אבן הבניין של כל השרשרות האלה - רשימה מקושרת, מחסנית, תור ואפילו עצים - היא מחלקה אחת פשוטה בשם Node. זו בדיוק המחלקה שמופיעה בשאלון 899271, ובדיוק בשם ובחתימה הזו.

1. מה זה Node?

Node (צומת) הוא אובייקט קטן שמחזיק שני דברים בלבד: ערך (value), ו הפניה לצומת הבא בשרשרת (next). אם אין צומת הבא - ה-next שווה ל-null. שרשרת שלמה נבנית פשוט מכך שכל צומת "מצביע" על הצומת שאחריו.

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

2. מחלקת Node - החתימה הסטנדרטית

זו מחלקה גנרית (Node<T>) - היא יכולה להחזיק ערך מכל טיפוס. חשוב לזכור את שמות המתודות בדיוק כפי שהן, כי בשאלון משתמשים בהן ישירות בלי להגדיר אותן מחדש:

⁦C#⁩

public class Node<T> {
    private T value;
    private Node<T> next;

    public Node(T value) { ... }
    public Node(T value, Node<T> next) { ... }

    public T GetValue() { ... }
    public Node<T> GetNext() { ... }
    public bool HasNext() { ... }      // true אם יש צומת אחרי זה

    public void SetValue(T value) { ... }
    public void SetNext(Node<T> next) { ... }
}
            

HasNext() שקול לבדיקה אם GetNext() שונה מ-null - אבל בבגרות תמיד משתמשים במתודה הנתונה (HasNext) ולא ניגשים לשדות הפרטיים ישירות. השדות private, ואי אפשר לגעת בהם מבחוץ בכלל.

3. בניית שרשרת

בונים שרשרת "מהסוף להתחלה" - קודם יוצרים את הצומת האחרון (בלי next), ואז כל צומת שנוצר לפניו מקבל אותו כפרמטר השני:

⁦C#⁩

Node<string> third = new Node<string>("גורי");            // אין next - הצומת האחרון
Node<string> second = new Node<string>("שרה", third);     // מצביע על third
Node<string> first = new Node<string>("דני", second);     // מצביע על second

// first הוא "ראש" השרשרת - הדרך היחידה להגיע לכל השאר
            
diagram
  first                    second                   third
[ "דני"  | next ●] ──► [ "שרה"  | next ●] ──► [ "גורי" | next X ]

כל תא בתרשים הוא צומת Node אחד: משבצת ה-value מחזיקה את הערך, ומשבצת ה-next היא חץ לצומת הבא - חוץ מהצומת האחרון, שם ה-next הוא null (מסומן כ-X בתרשים). first הוא לא צומת בפני עצמו - הוא סתם השם שנתנו למשתנה שמצביע על הצומת הראשון.

4. מעבר על השרשרת (Traversal)

כדי לעבור על כל הצמתים בלי לאבד את הראש, משתמשים במשתנה עזר שמתקדם צעד בכל פעם:

⁦C#⁩

Node<string> current = first;
while (current.HasNext()) {
    Console.WriteLine(current.GetValue());
    current = current.GetNext();
}
Console.WriteLine(current.GetValue());   // הצומת האחרון - עדיין צריך להדפיס אותו!
            

current = first - לעולם לא לשנות את first עצמו, כדי לא לאבד את הראש של השרשרת. הלולאה רצה כל עוד יש עוד צומת אחרי הנוכחי - ולכן היא עוצרת לפני עיבוד הצומת האחרון, שנשאר ומטופל בנפרד אחרי הלולאה.

5. טעויות נפוצות

שכחת הצומת האחרון: לולאה שרצה while (current.HasNext()) בלי שורת ה-Console.WriteLine שאחריה תדפיס את כל הצמתים חוץ מהאחרון.

איבוד הראש: ריצה על השרשרת ישירות עם first = first.GetNext() "אוכלת" את המשתנה שמחזיק את תחילת השרשרת - צריך תמיד משתנה עזר נפרד כמו current.

גישה ישירה לשדות: אין גישה ל-value או ל-next מבחוץ - רק דרך GetValue(), GetNext() ו-HasNext().

🎓 זווית הבגרות

איך זה מופיע בבגרות: Node היא אבן הבניין שעומדת מאחורי כל שאלת מבני נתונים בשאלון 899271 - Stack, Queue, רשימה מקושרת ואפילו עצים (BinNode) בנויים עליה.

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

טעות נפוצה: לאבד את ראש השרשרת (first) על ידי הזזתו ישירות, במקום להשתמש במשתנה עזר נפרד כמו current.

מה לזכור למבחן: תבנית המעבר הקבועה היא while (current.HasNext()) {...; current = current.GetNext();}, ואז טיפול נפרד בצומת האחרון אחרי הלולאה.

6. תרגול

מה יודפס למסך על ידי הקוד הבא?

⁦C#⁩
Node<string> third = new Node<string>("גורי");
Node<string> second = new Node<string>("שרה", third);
Node<string> first = new Node<string>("דני", second);

Node<string> current = first.GetNext();
Console.WriteLine(current.GetValue());

הקוד הבא בונה שרשרת על ידי שינוי מצביעים בעזרת SetNext, לא בבנאי - מה יודפס למסך?

⁦C#⁩
Node<string> a = new Node<string>("א");
Node<string> b = new Node<string>("ב");
a.SetNext(b);

Node<string> c = new Node<string>("ג");
b.SetNext(c);

Console.WriteLine(a.GetNext().GetNext().GetValue());

כתבו את הביטוי שבודק אם לצומת current יש צומת אחרי.

כתבו את שורת הקוד שמקדמת את current לצומת הבא בשרשרת.

כתבו את שורת הקוד שמדפיסה את הערך של הצומת הנוכחי.

פרק 10 - רקורסיה פרק 12 - מחסנית (Stack)