520 likes | 1.01k Views
สแตก และคิว (Stack & Queue). FIFO และ LIFO. F irst I n F isrt O ut : FIFO หมายถึงข้อมูลที่ เข้ามา ในลิสต์ ก่อน จะถูก นำออก จากลิสต์เป็น ลำดับแรก ตัวอย่างได้แก่การยืนรอคิวเพื่อซื้อตั๋ว
E N D
FIFO และ LIFO • First In Fisrt Out : FIFOหมายถึงข้อมูลที่เข้ามาในลิสต์ก่อน จะถูกนำออกจากลิสต์เป็นลำดับแรก ตัวอย่างได้แก่การยืนรอคิวเพื่อซื้อตั๋ว • Last In First Out : LIFOหมายถึงข้อมูลที่เข้ามาในลิสต์เป็นลำดับสุดท้าย จะถูกนำออกจากลิสต์เป็นอันดับแรก ตัวอย่างได้แก่การนำชั้นของปิ่นโตเข้าและออกจากเถาปิ่นโต
สแตก(stack) • เป็นโครงสร้างข้อมูลแบบเชิงเส้น ที่มีการใส่ข้อมูลเข้า และนำข้อมูลออกเพียงด้านเดียว ดังนั้น ข้อมูลที่เข้าไปอยู่ใน stack ก่อนจะออกจาก stack หลังข้อมูลที่เข้าไปใน stack ทีหลัง นั่นคือ การ "เข้าทีหลังแต่ออกก่อน" (Last In First Out : LIFO)
การกระทำ(Operation) ที่เกี่ยวข้องกับโครงสร้างข้อมูลแบบ Stack • ปฏิบัติการพื้นฐานของสแตกได้แก่ push คือการนำข้อมูลเก็บในสแตก และ pop คือการนำข้อมูลออกจากสแตก ซึ่งทั้งสองกระบวนการ จะกระทำที่ส่วนบนสุดของสแตกเสมอ โดยปกติแล้วมักกำหนดให้มีตัวชี้ส่วนบนสุดของสแตก เรียกว่า topส่วนปฏิบัติการอื่น ๆ เป็นปฏิบัติการที่เกี่ยวเนื่องกับการ push และ pop มีดังนี้ • การสร้างสแตก (CREATE) • การทดสอบว่า stack ว่างหรือไม่(EMPTY) • การทดสอบว่า stack เต็มหรือไม่(FULL) • การทำให้ stack เป็น stack ว่าง(CLEAR)
การนำข้อมูลเข้าสู่สแตก (Push) กระทำที่ส่วนบนของสแตก (Top) ซึ่งต้องมีการตรวจสอบก่อนว่าสแตกเต็มหรือไม่ • และการนำข้อมูลออกจากสแตก (Pop) กระทำที่ส่วนบนของสแตกเช่นกัน โดยตรวจสอบว่ามีสมาชิกอยู่ในสแตกหรือไม่ (ตรวจสอบว่าสแตกว่างเปล่าหรือไม่)
การนำข้อมูลเข้าไปในกองซ้อน (Push) • เป็นการดำเนินการที่นำข้อมูลเข้าไปเก็บไว้ด้านบนสุดของกองซ้อน (Top of the Stack) เรื่อย ๆ จนกว่ากองซ้อนไม่สามารถนำข้อมูลเข้าไปเก็บได้ • จะเรียกว่า กองซ้อนเต็ม (Stack Full)
ตัวอย่างการนำข้อมูลเข้าตัวอย่างการนำข้อมูลเข้า 90 Stack Full 1. Top = 0 2. Top = Top + 1 4 10 3. Stack[Top] = 40 15 60 3 2 1 Top 0 Stack
การนำข้อมูลออกจากกองซ้อน (Pop) • การทำงานจะตรงข้ามกับ Push • จะดึงเอาข้อมูลที่อยู่บนสุดออกมาก่อน แต่ก่อนที่จะดึงจะมีการตรวจสอบว่ากองซ้อนว่างหรือไม่ • ถ้าว่างจะไม่สามารถนำข้อมูลออกได้ แสดงว่ากองซ้อนว่าง (Stack Empty) • ถ้าไม่ว่างจะนำเอาข้อมูลออกแล้วเลื่อนตัวชี้ไปยังตำแหน่งถัดลงไป
Temp 4 3 2 1 0 Stack ตัวอย่างการนำข้อมูลออก 1. Temp = Stack[Top] Top 60 2. Top = Top - 1 40 Stack Empty 15 10
การสร้าง stack ด้วย Array • หมายถึง การแทนที่ข้อมูลของ stack ด้วย arrayซึ่ง เป็นการจัดสรรเนื้อที่หน่วยความจำแบบ staticนั่นคือ • มีการกำหนดขนาดของ stack ล่วงหน้าว่ามีขนาดเท่าใด และจะมีการจัดสรรเนื้อที่หน่วยความจำให้เลย
การแทนที่โครงสร้างข้อมูลแบบกองซ้อนด้วยแถวลำดับการแทนที่โครงสร้างข้อมูลแบบกองซ้อนด้วยแถวลำดับ • แบบลำดับจะต้องมีการจองพื้นที่หน่วยความจำไว้ล่วงหน้า ว่าจะมีขนาดเท่าใด • โดยแถวลำดับนี้จะปิดปลายด้านหนึ่งไว้ เพื่อให้ข้อมูลเข้า-ออกทางเดียว • ปฏิบัติการมี 4 ขั้นตอนคือ • การสร้าง • การ Push • การ Pop • การ แสดง
การสร้างกองซ้อนด้วยแถวลำดับการสร้างกองซ้อนด้วยแถวลำดับ • เป็นการเตรียมเนื้อที่ในหน่วยความจำไว้สำหรับเก็บข้อมูล • ตัวอย่างในภาษาซี คือ int Stack[4]; • การนำข้อมูลเข้าและออกจากหน่วยความจำด้วยแถวลำดับ ก็เหมือนกับที่ยกตัวอย่างไปแล้ว Stack
การแสดงข้อมูลที่อยู่ในกองซ้อนด้วยแถวลำดับการแสดงข้อมูลที่อยู่ในกองซ้อนด้วยแถวลำดับ • จะเป็นการดึงข้อมูลตั้งแต่ตำแหน่งแรกจนถึงตำแหน่งที่ Topชี้อยู่ออกมาแสดง • หรือจะกลับกันคือ นำข้อมูลจากตำแหน่ง Top ชี้อยู่จนถึงตำแหน่งที่ 0 ออกมาแสดง
แสดงข้อมูล 4 3 2 1 0 Stack Top I 60 60 40 40 15 15 10 10
การสร้าง stack ด้วย Link List • หมายถึง การแทนที่ข้อมูลของ stack ด้วย Link list ซึ่งเป็นการจัดสรรเนื้อที่หน่วยความจำแบบ Dynamic นั่นคือ หน่วยความจำจะถูกจัดสรรเมื่อมีการของใช้จริงๆ ระหว่างการประมวลผลโปรแกรมผ่านตัวแปรชนิด Pointer
การแทนที่โครงสร้างข้อมูลกองซ้อนด้วยรายการโยงการแทนที่โครงสร้างข้อมูลกองซ้อนด้วยรายการโยง • เป็นการแทนที่ที่มีความยืดหยุ่นมาก • เนื่องจากไม่ต้องกำหนดหรือจองหน่วยความจำล่วงหน้า • ข้อมูลที่เก็บในกองซ้อนมีจำนวนเท่าใดก็ได้ การปฏิบัติการมี 4 ขั้นตอนคือ การสร้าง, การ Push, การ Pop และการแสดง
data การสร้างกองซ้อนด้วยรายการโยง • เหมือนกับในบทที่ 3 ในที่นี้จะยกตัวอย่างกรณีที่เป็น รายการโยงแบบเดี่ยว การสร้างจะเป็นดังนี้ typedef struct node { int data; struct node *Next; } node; node *Top; int info; node Next
การนำข้อมูลเข้าไปในกองซ้อนแบบรายการโยงการนำข้อมูลเข้าไปในกองซ้อนแบบรายการโยง P 1. Top = Null 2. New(P) Top 80 ^ 3. Data(p) = 80 4. Next(p) = Null 5. Top = p
การนำข้อมูลเข้าไปในกองซ้อนแบบรายการโยงการนำข้อมูลเข้าไปในกองซ้อนแบบรายการโยง • เพิ่มข้อมูล 90 เข้าไปในรายการโยง P Top 1. New(P) Top 90 80 ^ 2. Data(P) = 90 3. Next(P) = Top 4. Top = p
การนำข้อมูลเข้าไปในกองซ้อนแบบรายการโยงการนำข้อมูลเข้าไปในกองซ้อนแบบรายการโยง P Top Top 120 90 80 ^ 1. New(P) 3. Next(P) = Top 2. Data(P) = 120 4. Top = p
120 การนำข้อมูลออกจากกองซ้อนด้วยรายการโยง Temp Top Top 90 80 ^ 1. Temp=Top 2. Top = Next(Top)
90 การนำข้อมูลออกจากกองซ้อนด้วยรายการโยง Temp Top Top ^ 80 1. Temp=Top 2. Top = Next(Top)
80 การนำข้อมูลออกจากกองซ้อนด้วยรายการโยง Temp Top = NULL Top 1. Temp=Top 2. Top = Next(Top)
การนำข้อมูลออกจากกองซ้อนด้วยรายการโยงการนำข้อมูลออกจากกองซ้อนด้วยรายการโยง Stack Empty Top = NULL 1. Temp=Top
การแสดงข้อมูลที่อยู่ในกองซ้อนด้วยรายการโยงการแสดงข้อมูลที่อยู่ในกองซ้อนด้วยรายการโยง P P P 120 Top 120 90 80 ^ 90 80
การประยุกต์ใช้ stack • โครงสร้างข้อมูลแบบ stack มีการประยุกต์ใช้มากในการเขียนโปรแกรมของสาขาวิทยาการคอมพิวเตอร์ เช่น การจัดสรรหน่วยความจำในการประมวลผลโปรแกรม การตรวจสอบอักขระสมดุล(Balancing Symbol) และการคำนวณนิพจน์คณิตศาสตร์
การเรียกใช้โปรแกรมย่อยการเรียกใช้โปรแกรมย่อย • การเรียกโปรแกรมย่อยมีความแตกต่างกับการกระโดดทั่วไป เนื่องจากภายหลังที่โปรแกรมย่อยทำงานเสร็จ หน่วยประมวลผลจะต้องสามารถกระโดดกลับมาทำงานในโปรแกรมหลักต่อไปได้ดังนั้นการเรียกใช้โปรแกรมย่อยนั้นจะต้องมีการเก็บตำแหน่งของคำสั่งที่ทำงานอยู่เดิมด้วย และเมื่อจบโปรแกรมย่อยโปรแกรมจะต้องกระโดดกลับมาทำงานที่เดิม โดยใช้ข้อมูลที่เก็บไว้ ภาพและอัลกอริทึมแสดงตัวอย่างการเรียกใช้โปรแกรมย่อย
PROGRAM MAIN ...... CALL Sub1 PRINT Q .... END MAIN PROCEDURE Sub1 .... CALL Sub2 A:=A+B ... END Sub1 PROCEDURE Sub2 ... END Sub2
การประยุกต์ใช้โครงสร้างข้อมูลแบบกองซ้อนการประยุกต์ใช้โครงสร้างข้อมูลแบบกองซ้อน • การเรียกใช้โปรแกรมย่อยอื่น • โปรแกรมย่อยที่เรียกใช้ตัวเอง • Factorial • การคำนวณนิพจน์ทางคณิตศาสตร์
B B1 ----- Call B1 ----- Return ----- ----- Return 1500 ----- Call B ----- Call C สิ้นสุดโปรแกรม ----- ----- Return 1000 C การเรียกใช้โปรแกรมอื่น 1500 1000 Stack
Factorial • สัญลักษณ์แฟกตอเรียลเขียนเป็น n! 0! = 1 1! = 1 2! = 2 x 1 3! = 3 x 2 x 1 n! = n x (n-1) x (n-2) x …x 2 x 1
Push 3! 4 3! = 3 * 2! 2! = 2 * 1! 1 3 1! = 1 * 0! 2 2 Pop 0! = 1 1 3 1! = 1 * 1 Top 0 Stack 2! = 2 * 1 3! = 3 * 2
การตรวจสอบอักขระสมดุล(Balancing Symbol) • ในการตรวจสอบอักขระสมดุลนั้น คอมไพเลอร์ได้นำแนวคิดโครงสร้างข้อมูลแบบ Stack มาประยุกต์ โดยมีวิธีการดังนี้ • 1. ให้อ่านอักขระทีละตัว • - ถ้าอักขระเป็นอักขระเปิด เช่น {,(,[ เป็นต้น ให้PUSH ลง stack • - ถ้าอักขระเป็นอักขระปิด เช่น },),] เป็นต้น ให้ตรวจสอบว่าอักขระบน TOP ของ stack เป็นอักขระเปิดที่คู่กันหรือไม่ • - ถ้าใช่ ให้ POP อักขระนั้นออกจาก stack • - ถ้าไม่ใช่ ให้แสดงผล error • 2.เมื่ออ่านอักขระหมดแล้ว แต่ stack ไม่เป็น stack ว่าง ให้แสดงผล error
โพลิช โนเตชัน(Polish Notation) • เป็นวิธีการจัดรูปแบบของสมการใหม่ โดยการย้ายตำแหน่งของเครื่องหมายและตัวดำเนินการ เช่น 2*3 เขียนเป็น *23เป็นต้น โดยมีรูปแบบการเขียนสมการ ดังนี้ • Prefix: การเขียนสมการโดยให้เครื่องหมายอยู่หน้าตัวดำเนินการ • เช่น * + 5 3 2 • Infix : การเขียนสมการโดยให้เครื่องหมายอยู่ระหว่างตัวดำเนินการ • เช่น (5+3)*2 • Postfix : การเขียนสมการโดยให้เครื่องหมายอยู่หลังตัวดำเนินการ • เช่น 5 3 + 2 *
Algorithm การคำนวณแบบ Postfix • ให้อ่านข้อมูลจากซ้ายไปขวาทีละตัว • ถ้าพบตัวถูกดำเนินการ(ตัวเลข) ให้ push stack • ถ้าพบตัวดำเนินการ(เครื่องหมาย) ให้ pop item บนสุดของ stack 2 ตัว แล้วทำการคำนวณตามเครื่องหมายที่พบ แล้วนำผลลัพธ์ที่ได้ push stack • ทำซ้ำจนกระทั่งหมดข้อมูล
วิธีการเปลี่ยน Infix เป็น Postfix • 1. Completely parnthesize th infix notation tospecify the order of all operations • 2. Move each operator to the space held by itscorressponding right parenthesis • 3. Remove all parenthesis • ตัวอย่าง A/B^C+D*E-A*C • ผลลัพธ์ข้อ 1--> (((A/(B^C))+(D*E))-(A*C)) • ผลลัพธ์ข้อ 2--> (((A(BC)^)/(DE)*)+(AC)*) - • ผลลัพธ์ข้อ 3--> ABC^/DE*+AC*-
วิธีการเปลี่ยน Infix เป็น Postfix • Algorithm การเปลี่ยน Infix เป็น Postfix • ให้ EXP เป็นสมการคณิตศาสตร์ที่เป็น Infix และ Stack เป็น stack ใด ๆ NEXP เป็นสมการที่เป็น Postfix • 1. ใส่ “(“ เข้าไปใน Stack • 2. อ่าน EXP จากซ้ายไปขวา • 2.1 ถ้าพบตัวถูกดำเนินการ(ตัวเลข) ให้ใส่เข้าไปใน NEXP • 2.2 ถ้าพบ “(“ ให้ push ใส่ stack
วิธีการเปลี่ยน Infix เป็น Postfix • 2.3 ถ้าพบตัวดำเนินการ(เครื่องหมาย) ให้ทำดังนี้ • - ให้ pop ตัวดำเนินการ ทุกตัวที่มีลำดับความสำคัญกว่าตัวดำเนินการที่พบใน 2.3 ออกมาใส่ใน NEXP ให้หมด • - นำตัวดำเนินการที่พบใน 2.3 push เข้าใน stack แทนที่ • 2.4 ถ้าพบ “)” ให้ทำดังนี้ • - ให้ push ตัวดำเนินการ ทุกตัวมาใส่ไว้ใน NEXP ให้หมดจนพบ “(“ • - push “(“ ทิ้ง • 3. จบการทำงาน
ความสำคัญของตัวดำเนินการความสำคัญของตัวดำเนินการ
แบบฝึกหัด • จงเปลี่ยนนิพจน์อินฟิกซ์ ต่อไปนี้ให้เป็นโพสฟิกซ์ • 1. ((A+B)*C)-D • 2. A*C/D • 3. 10+15*20/6 • 4. 5*4+(8/2) • 5. 10/(2+3)+(5+6)*9 • 6. A*(B-C/D)+E