Stack
FIFO และ LIFO First In First Out : FIFO หมายถึงข้อมูลที่เข้ามาในลิสต์ก่อน จะ ถูกนำออกจากลิสต์เป็นลำดับแรก ตัวอย่างได้แก่การยืนรอคิวเพื่อซื้อตั๋ว Last In First Out : LIFO หมายถึงข้อมูลที่เข้ามาในลิสต์เป็น ลำดับสุดท้าย จะถูกนำออกจากลิสต์เป็นอันดับแรก ตัวอย่างได้แก่การนำชั้นของ ปิ่นโตเข้าและออกจากเถาปิ่นโต
Stack เป็นโครงสร้างข้อมูลแบบเชิงเส้น ที่มีการใส่ข้อมูลเข้า และ นำข้อมูลออกเพียงด้านเดียว ดังนั้น ข้อมูลที่เข้าไปอยู่ใน stack ก่อนจะออกจาก stack หลังข้อมูลที่เข้าไปใน stack ทีหลัง นั่นคือ การ "เข้าทีหลังแต่ออกก่อน" (Last In First Out : LIFO)
การกระทำ(Operation) ที่เกี่ยวข้องกับโครงสร้างข้อมูลแบบ Stack ปฏิบัติการพื้นฐานของStackได้แก่ push คือการนำข้อมูลเก็บในStack และ pop คือ การนำข้อมูลออกจากStack ซึ่งทั้งสองกระบวนการ จะกระทำที่ส่วนบนสุดของStack เสมอ โดยปกติแล้วมักกำหนดให้มีตัวชี้ส่วนบนสุดของStack เรียกว่า top ส่วน ปฏิบัติการอื่น ๆ เป็นปฏิบัติการที่เกี่ยวเนื่องกับการ push และ pop มีดังนี้ การสร้างStack (CREATE) การทดสอบว่า stack ว่างหรือไม่(EMPTY) การทดสอบว่า stack เต็มหรือไม่(FULL) การทำให้ stack เป็น stack ว่าง(CLEAR)
การนำข้อมูลเข้าสู่Stack (Push) กระทำที่ส่วนบนของStack (Top) ซึ่งต้องมีการ ตรวจสอบก่อนว่าStackเต็มหรือไม่ และการนำข้อมูลออกจากStack (Pop) กระทำที่ส่วนบนของStackเช่นกัน โดย ตรวจสอบว่ามีสมาชิกอยู่ในStackหรือไม่ (ตรวจสอบว่าStackว่างเปล่าหรือไม่)
การนำข้อมูลเข้าไปในกองซ้อน (Push) เป็นการดำเนินการที่นำข้อมูลเข้าไปเก็บไว้ด้านบนสุดของกอง ซ้อน (Top of the Stack) เรื่อย ๆ จนกว่ากองซ้อนไม่สามารถนำ ข้อมูลเข้าไปเก็บได้ จะเรียกว่า กองซ้อนเต็ม (Stack Full)
การนำข้อมูลออกจากกองซ้อน (Pop) การทำงานจะตรงข้ามกับ Push จะดึงเอาข้อมูลที่อยู่บนสุดออกมาก่อน แต่ก่อนที่จะดึงจะมีการตรวจสอบว่ากองซ้อนว่าง หรือไม่ ถ้าว่างจะไม่สามารถนำข้อมูลออกได้ แสดงว่ากองซ้อนว่าง (Stack Empty) ถ้าไม่ว่างจะนำเอาข้อมูลออกแล้วเลื่อนตัวชี้ไปยังตำแหน่งถัดลง ไป
ให้ Y เป็นสแตกเก็บค่าตัวเลขได้ไม่เกิน 6 ตัว Push(‘2’),Push(‘5’),Push(‘3’) Pop(),Push(‘9’), Push(‘0’) Push(‘4’) Push(‘6’),Pop()
เริ่มต้นจากการสร้างสแตก Yขึ้นมาทำงานจำได้สแตกว่าง ไม่มีสมาชิกโดยตัวชี้สแตก Top ยังไม่มีค่า
2 นำค่า 2 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘2’) สแตก Y=[2] ตัวชี้สแตก Top = 2 Top
2 5 นำค่า 5 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘5’) สแตก Y=[5] ตัวชี้สแตก Top = 5 Top
2 5 3 นำค่า 3 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘3’) สแตก Y=[3] ตัวชี้สแตก Top = 3 Top
ต้องการดึงค่าออกมาโดยใช้Pop() 5 2 ต้องการดึงค่าออกมาโดยใช้Pop() สแตก Y=[2,5,3]ตัวชี้สแตก Top = 3 Top
นำค่า 9 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘9’) สแตก Y=[9] ตัวชี้สแตก 2 5 9 นำค่า 9 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘9’) สแตก Y=[9] ตัวชี้สแตก Top = 9 Top
นำค่า 0 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘0’) สแตก Y=[0] ตัวชี้สแตก Top = 0 2 5 9 Top
นำค่า 4 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘4’) สแตก Y=[4] ตัวชี้สแตก Top = 4 2 5 9 4 Top
นำค่า 6 เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(‘6’) สแตก Y=[6] ตัวชี้สแตก Top = 6 2 5 9 4 6 Top
Implementation of Stacks Any list implementation could be used to implement a stack Arrays (static: the size of stack is given initially) Linked lists (dynamic: never become full) We will explore implementations based on array and linked list Let’s see how to use an array to implement a stack first
Array Implementation Need to declare an array size ahead of time มีทางให้ข้อมูลเข้า และ ข้อมูลออก เพียงด้านเดียว Associated with each stack is TopOfStack for an empty stack, set TopOfStack to -1 Push (1) Increment TopOfStack by 1. (2) Set Stack[TopOfStack] = X Pop (1) Set return value to Stack[TopOfStack] (2) Decrement TopOfStack by 1 These operations are performed in very fast constant time
การสร้างกองซ้อนด้วยแถวลำดับ เป็นการเตรียมเนื้อที่ในหน่วยความจำไว้สำหรับเก็บข้อมูล ตัวอย่างในภาษาซี คือ int Stack[4]; การนำข้อมูลเข้าและออกจากหน่วยความจำด้วยแถวลำดับ ก็เหมือนกับที่ยกตัวอย่าง ไปแล้ว Stack
Stack class class Stack { public: Stack(int size = 10); // constructor ~Stack() { delete [] values; } // destructor bool IsEmpty() { return top == -1; } bool IsFull() { return top == maxTop; } double Top(); void Push(const double x); double Pop(); void DisplayStack(); private: int maxTop; // max stack size = size - 1 int top; // current top of stack double* values; // element array };
Stack class Attributes of Stack Operations of Stack maxTop: the max size of stack top: the index of the top element of stack values: point to an array which stores elements of stack Operations of Stack IsEmpty: return true if stack is empty, return false otherwise IsFull: return true if stack is full, return false otherwise Top: return the element at the top of stack Push: add an element to the top of stack Pop: delete the element at the top of stack DisplayStack: print all the data in the stack
Create Stack The constructor of Stack Allocate a stack array of size. By default, size = 10. When the stack is full, top will have its maximum value, i.e. size – 1. Initially top is set to -1. It means the stack is empty. Stack::Stack(int size /*= 10*/) { maxTop = size - 1; values = new double[size]; top = -1; } Although the constructor dynamically allocates the stack array, the stack is still static. The size is fixed after the initialization.
Push Stack void Push(const double x); Push an element onto the stack If the stack is full, print the error information. Note top always represents the index of the top element. After pushing an element, increment top. void Stack::Push(const double x) { if (IsFull()) cout << "Error: the stack is full." << endl; else values[++top] = x; }
Pop Stack double Pop() Pop and return the element at the top of the stack If the stack is empty, print the error information. (In this case, the return value is useless.) Don’t forgot to decrement top double Stack::Pop() { if (IsEmpty()) { cout << "Error: the stack is empty." << endl; return -1; } else { return values[top--];
Stack Top double Top() Return the top element of the stack Unlike Pop, this function does not remove the top element double Stack::Top() { if (IsEmpty()) { cout << "Error: the stack is empty." << endl; return -1; } else return values[top];
Printing all the elements void DisplayStack() Print all the elements void Stack::DisplayStack() { cout << "top -->"; for (int i = top; i >= 0; i--) cout << "\t|\t" << values[i] << "\t|" << endl; cout << "\t|---------------|" << endl; }
Using Stack result int main(void) { Stack stack(5); stack.Push(5.0); stack.DisplayStack(); cout << "Top: " << stack.Top() << endl; stack.Pop(); while (!stack.IsEmpty()) stack.Pop(); return 0; }
การประยุกต์ใช้ stack โครงสร้างข้อมูลแบบ stack มีการประยุกต์ใช้มากในการเขียนโปรแกรมของสาขา วิทยาการคอมพิวเตอร์ เช่น การจัดสรรหน่วยความจำในการประมวลผลโปรแกรม (Function Call) รวมทั้ง โปรแกรมเรียกใช้ตัวเอง (Recursive) การตรวจสอบอักขระสมดุล(Balancing Symbol) การคำนวณนิพจน์คณิตศาสตร์
Function Call การเรียกใช้ Function หรือ Procedure หรือโปรแกรมย่อยในภาษาที่ ไม่มีการ Recursive เมื่อมีการเรียกใช้ Function ก็จะทำการ Push Function to Stack และเมื่อมีการ Return หรือจบการทำงานของ Function แล้วจะต้อง Pop Function from Stack
การเรียกใช้โปรแกรมย่อย การเรียกโปรแกรมย่อยมีความแตกต่างกับการกระโดดทั่วไป เนื่องจากภายหลัง ที่โปรแกรมย่อยทำงานเสร็จ หน่วยประมวลผลจะต้องสามารถกระโดดกลับมาทำงานใน โปรแกรมหลักต่อไปได้ ดังนั้นการเรียกใช้โปรแกรมย่อยนั้นจะต้องมีการเก็บ ตำแหน่งของคำสั่งที่ทำงานอยู่เดิมด้วย และเมื่อจบโปรแกรมย่อยโปรแกรม จะต้องกระโดดกลับมาทำงานที่เดิม โดยใช้ข้อมูลที่เก็บไว้ ภาพและอัลกอริทึมแสดง ตัวอย่างการเรียกใช้โปรแกรมย่อย
PROGRAM MAIN ...... CALL Sub1 PRINT Q .... END MAIN PROCEDURE Sub1 CALL Sub2 A:=A+B ... END Sub1 PROCEDURE Sub2 END Sub2
Balancing Symbols Example : {x+(y-[a+b])*c-[(d+e)]}/(h-(j-(k-[l-n])))
การตรวจสอบอักขระสมดุล(Balancing Symbol) ในการตรวจสอบอักขระสมดุลนั้น คอมไพเลอร์ได้นำแนวคิด โครงสร้างข้อมูลแบบ Stack มาประยุกต์ โดยมีวิธีการดังนี้ 1. ให้อ่านอักขระทีละตัว - ถ้าอักขระเป็นอักขระเปิด เช่น {,(,[ เป็นต้น ให้ PUSH ลง stack - ถ้าอักขระเป็นอักขระปิด เช่น },),] เป็นต้น ให้ตรวจสอบว่า อักขระบน TOP ของ stack เป็นอักขระเปิดที่คู่กันหรือไม่ - ถ้าใช่ ให้ POP อักขระนั้นออกจาก stack - ถ้าไม่ใช่ ให้แสดงผล error 2.เมื่ออ่านอักขระหมดแล้ว แต่ stack ไม่เป็น stack ว่าง ให้แสดงผล error