מבני נתונים ואלגוריתמים - מחברת קורס/מבני נתונים/תורים

דף זה עוסק במבנה נתונים שלו נתן לדחוף ולשלוף איברים. מבנה זה צריך להבטיח שהאיבר הראשון שהוכנס הוא האיבר הראשון שיישלף.


כדאי לדעת:

#לפעמים קוראים למבנה זה FIFO, או "first in - first out".
  1. מחסניות עוסק בLIFO.
  2. בספר הקורס, הפרק "Elementary Data Structures" מכסה נושא זה.


מימוש C++

std::queue

ממשק עריכה

להלן ממשק אפשרי לתור:

# Pushes (inserts) a value (v) to a queue (q).
Enqueue(q, v)

# Pops (removes) from a queue (q) the oldest value Enqueue()ed 
#	(that has not yet been Dequeue()ed).
Dequeue(q)

# Returns the oldest value Dequeue()ed to a queue (q) 
# 	(that has not yet been Dequeue()ed).
Front(q)

# Returns the number of values inside a queue (q).
Size(q)

להלן דוגמה לשימוש בתור:

1	Enqueue(q, 1)
2	Enqueue(q, 3)
3	Enqueue(q, 2)

	# Prints 3
4	print Size(q)

	# Prints 1
5	Print Front(q)

6	Dequeue(q)

	# Prints 2
7	print Size(q)

	# Prints 3
8	Print Front(q)


הגדרה:

לעתים יש מבני נתונים שנתן לממש אותם בדרכים שונות. כדאי להבדיל בין הדברים הבאים:

  • ממשק (interface) - מה המבנה עושה
  • מימוש (implementation) - איך המבנה עושה זאת

אלה המושגים הנהוגים בהנדסת תכנה. בתחום מבני הנתונים והאלגוריתמים, לפעמים קוראים למבנה נתונים שרק הממשק שלו הוצג - ADT, או abstract data type.‏


 

שימו לב:

למרבה הצער, אין ממשק מוסכם לתור. אנו השתמשנו בשמות הפעולות Enqueue,‏‏ Dequeue,‏ ‏ ‏ וFront;‏ יש המשתמשים בשמות הפעולות Push,‏ Pop,‏ וFirst; ‏ יש עוד ווריאציות. במהלך הקורס, אם תתקל בממשקים אחרים (לדוגמה במבחנים משנים קודמות), ייתכן שתיאלץ להפעיל מעט גמישות בהבנת הממשק.

מימושים עריכה

באופן דומה למה שראינו במחסניות, גם תורים ניתנים למימוש ע"י מערכים או רשימות מקושרות.

מימוש מערך עריכה

כאשר ידוע מראש מספר האיברים שיכולים לשכון בו זמנית בתור, לא קשה לממשו בעזרת מערך. לא נראה זאת כאן.

מימוש רשימה מקושרת עריכה

קל מאד (וכמעט מתבקש) לממש תור על ידי רשימה מקושרת. להלן מימוש על ידי רשימה מקושרת (דו-כוונית).

התור מכיל בתוכו שדה יחיד - רשימה מקושרת l.

Queue
	l # A list.

כעת יש שתי אפשרויות:

  1. נכניס איברים לסוף הרשימה, ונשלוף אותם מראשה.
  2. נכניס איברים לראש הרשימה ונשלוף אותם מסופה.

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

כדי לדחוף איבר לתור, נכניס אותו לראש הרשימה. להלן הפסוודו-קוד לפעולת Enqueue:

# Enqueues a value (v) in a queue (q)
Enqueue(q, v)
1	Insert-Front(q.l, v)

היות שבחרנו להכניס איברים לראש הרשימה, האיבר הראשון שנשלוף בכל פעם יהיה מסוף הרשימה:

# Dequeues a value from a (non-empty) queue (q), and returns this value.
Dequeue(q)
1	v = Back(q.l)
2	Delete-Back(q.l)
3	return v

נשים לב שבמימוש זה, ראש התור הוא למעשה סוף הרשימה:

# Returns the front (next to be dequeued) value from a (non-empty) queue (q).
Front(q)
1	return Back(q.l)

מימוש על ידי שתי מחסניות עריכה

אפשר לממש תור גם על ידי שתי מחסניות. נראה זאת בתרגילים.


הפרק הקודם:
מחסניות
תורים
תרגילים
הפרק הבא:
עצי חיפוש בינריים