stack queue...

32
Stack และ Queue เป็ นโครงสร ้างที่ใช ้เก็บข ้อมูลในอีกรูปแบบหนึ่งที่มีการนาไปใช ้อย่าง แพร่หลาย ซึ่งการจัดเก็บในรูปแบบทั้งสองนี้ได ้เลียนแบบมาจากเหตุการณ์ที่เกิดขึ้นใน ชีวิตประจาวันของเรา เช่น เราวางหนังสือซ ้อนกันเป็ นชั ้น ๆ (Stack) หรือ การเข ้าแถวเพื่อรอรับ การบริการต่าง ๆ หรือที่เรียกจนติดปากว่า เข ้าคิว (Queue) เช่น เข ้ารอการนาเงินไปฝากกับ ธนาคาร เข ้าคิวรอซื้อตั๋วหนัง ในบทนี้เราจะพูดถึง Stack และ Queue ที่ใช ้ array และ Linked- List เป็ นโครงสร ้างในการเก็บข ้อมูล หลังจากจบบทเรียนนี้แล ้ว ผู ้อ่านจะได ้ทราบถึง o การออกแบบโครงสร ้าง และการใช ้งานของ Stack o การนาข ้อมูล เข ้าสู่ หรือ ออกจาก Stack o การดูข ้อมูลที่มีอยู่ใน Stack โดยไม่มีการนาออก o การใช ้ Stack ในรูปแบบต่าง ๆ o การออกแบบโครงสร ้าง และการใช ้งานของ Queue o การนาข ้อมูล เข ้าสู่ หรือออกจาก Queue o การดูข ้อมูลที่มีอยู่ใน Queue โดยไม่มีการนาออก o การใช ้ Queue ในรูปแบบต่าง ๆ o การสร้าง Stack และ Queue ด ้วย Linked-List 3.1 Stack Stack เป็นการจัดเก็บข ้อมูลในแบบที่เรียกว่า Last-In, First-Out (LIFO) ซึ่งเป็นการจัดเก็บทีสามารถนาไปใช ้กับการเขียนโปรแกรมด ้านต่าง ๆ เช่น การตรวจสอบ (parsing หรือ analyzing) สมการทางคณิตศาสตร์ เช่น 3 * (5 + 89) ในการออกแบบทางสถาปัตยกรรมของ computer ส่วนใหญ่ก็ใช ้ stack เป็นตัวจัดเก็บ address หรือ instruction ต่าง ๆ ภาพที่ 3.1 การวางหนังสือเรียงกันเป็ นชั้น – stack of books Stack เป็ นการจัดเก็บข ้อมูลในลักษณะของการนาข ้อมูลมาวางซ ้อนกัน เหมือนกับการวางถ ้วย ชามที่เราคุ้นเคยกันอยู่ประจา (ถ ้าเราเคยอยู่ในครัวมาก่อน หรือไปกินก๋วยเตี ๋ยวบ่อย ๆ) หรือการ นาเอาหนังสือมาวางเรียงกันเป็ นชั้น ๆ ดังที่แสดงในภาพที่ 3.1 เราสามารถที่จะเอาคุณสมบัตินี้มา ใช ้ในการเก็บข ้อมูลต่าง ๆ ที่เราเห็นว่าเหมาะสม ดังตัวอย่างที่ได ้กล่าวมาแล ้ว การเขียน code บนสุด (top) - เข ้าหลังสุด ล่างสุด (bottom) - เข ้าก่อน

Upload: others

Post on 19-Jan-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue เปนโครงสรางทใชเกบขอมลในอกรปแบบหนงทมการน าไปใชอยางแพรหลาย ซงการจดเกบในรปแบบทงสองนไดเลยนแบบมาจากเหตการณทเกดข นในชวตประจ าวนของเรา เชน เราวางหนงสอซอนกนเปนชน ๆ (Stack) หรอ การเขาแถวเพอรอรบการบรการตาง ๆ หรอทเรยกจนตดปากวา เขาคว (Queue) เชน เขารอการน าเงนไปฝากกบธนาคาร เขาควรอซอตวหนง ในบทนเราจะพดถง Stack และ Queue ทใช array และ Linked-List เปนโครงสรางในการเกบขอมล หลงจากจบบทเรยนนแลว ผอานจะไดทราบถง o การออกแบบโครงสราง และการใชงานของ Stack o การน าขอมล เขาส หรอ ออกจาก Stack o การดขอมลทมอยใน Stack โดยไมมการน าออก o การใช Stack ในรปแบบตาง ๆ o การออกแบบโครงสราง และการใชงานของ Queue o การน าขอมล เขาส หรอออกจาก Queue o การดขอมลทมอยใน Queue โดยไมมการน าออก o การใช Queue ในรปแบบตาง ๆ o การสราง Stack และ Queue ดวย Linked-List

3.1 Stack Stack เปนการจดเกบขอมลในแบบทเรยกวา Last-In, First-Out (LIFO) ซงเปนการจดเกบทสามารถน าไปใชกบการเขยนโปรแกรมดานตาง ๆ เชน การตรวจสอบ (parsing หรอ analyzing) สมการทางคณตศาสตร เชน 3 * (5 + 89) ในการออกแบบทางสถาปตยกรรมของ computer สวนใหญกใช stack เปนตวจดเกบ address หรอ instruction ตาง ๆ

ภาพท 3.1 การวางหนงสอเรยงกนเปนชน – stack of books

Stack เปนการจดเกบขอมลในลกษณะของการน าขอมลมาวางซอนกน เหมอนกบการวางถวยชามทเราคนเคยกนอยประจ า (ถาเราเคยอยในครวมากอน หรอไปกนกวยเตยวบอย ๆ) หรอการน าเอาหนงสอมาวางเรยงกนเปนชน ๆ ดงทแสดงในภาพท 3.1 เราสามารถทจะเอาคณสมบตนมาใชในการเกบขอมลตาง ๆ ทเราเหนวาเหมาะสม ดงตวอยางทไดกลาวมาแลว การเขยน code

บนสด (top) - เขาหลงสด

ลางสด (bottom) - เขากอน

Page 2: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

70

ของ stack กไมยากเพยงแตเราก าหนดใหการน าขอมลเขา (push) และ การดงขอมลออก (pop) อยในกฎเกณฑของ stack คอ เขาหลงออกกอน (Last-In, First-Out) การใช array เปนทเกบขอมลของ stack นน ท าใหการเขยน code ของเราท าไดงายขน แตการน าเอา array มาใชนน กเปนททราบกนดอยแลววา มขดจ ากดในเรองของขนาดของ array คอ เราไมสามารถทจะขยายขนาดได ถาเราเลอกทจะก าหนดขนาดของ array กอนการสราง stack (ยกเวนวาเราจะใชเทคนคของ dynamic array ทไดพดถงกอนหนานในบทท 1) ตวอยางแรกจะเปนการออกแบบโครงสรางของ Stack ทใช array ทมความจ ากดในเรองของขนาด 3.1.1 Stack ทมขอจ ำกดในเรองของขนำด เราเรมตนดวยการสราง class ArrayStack ทม operation ตาง ๆ ทเกยวของกบ stack คอ การ

น าขอมลเขา (push) การดงขอมลออก (pop) การตรวจสอบวา stack มขอมลอยเตมหรอไมมขอมลอยเลย (full และ empty) หรอแมกระทงการแสดงขอมลทมอยใน stack ใน class ArrayStack ของเรา เราก าหนดตวแปรชอ stack เปน array ทใชในการเกบ object ท user ตองการใช และ ก าหนดให top เปนตวชถงขอมลทอยบนสดของ stack ขนาดของ stack จะมาจาก user เมอ constructor ถกเรยก เชน ArrayStack<Integer> stack = new ArrayStack<Integer>(10);

3.1.1.1 กำรน ำขอมลเขำส stack (push) การน าขอมลเขาส stack กเหมอนกบการน าขอมลเขาส array โดยทวไป เราเลอกทจะตรวจสอบถงความจของ stack กอนทเราจะน าขอมลเขา ซงถา stack ของเราเตมแลว เรากจะฟองไปยง user ทนท (และจะไมใสขอมลให) public void push(T obj) {

if(!full()) {

stack[++top] = obj;

numItems = top + 1;

}

else {

System.err.println("ERROR! Stack is full.");

System.exit(1);

}

}

ภาพท 3.2 การใสขอมลเขาส stack (push operation)

Operation

Book 5

Book 4

Book 3

Book 2

Book 1

Push

Book 5

Book 4

Book 3

Book 2

Book 1

Book 6

Book 6

Top

Top

Stack กอนการใส Book 6 Stack หลงจากการใส Book 6

Page 3: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

71

3.1.1.2 กำรดงขอมลออกจำก stack (pop) การดงขอมลออกจาก stack กเหมอนกบการลบขอมลออกจาก array เราเพยงแตดงเอาคาทอยในต าแหนงของ top มาใช พรอมกบลดคาของ top ลงหนงคา เพอให top ชไปยงขอมลตวถดไปทอยใน array (ตวใหมทอยบนสดใน stack) code ทเราเขยนขนนเราก าหนดใหมการสงคา null ใหกบผเรยกถา stack ของเราไมมขอมลอยเลย public T pop() {

if(empty())

return null;

return stack[top--];

}

ภาพท 3.3 การดงขอมลออกจาก stack (pop operation)

ส าหรบ method ตวอน ๆ กไมยากทจะท าความเขาใจ เราก าหนดใหคาของ top เมอไมมขอมลอยเลยเปน -1 เพราะฉะนน การตรวจสอบวา stack มขอมลหรอไม กตองตรวจสอบวาคาของ top เทากบ -1 หรอไม สวนการตรวจสอบวา stack มขอมลอยเตมแลวนน เรากตรวจสอบ top กบขนาดของ array – 1 เพอใหการจดการกบขอมลเปนไปไดอยางหลากหลาย เราจะก าหนดให stack ของเราเกบขอมลในรปแบบของขอมลดบ (Generic)1 ซงวธการดงกลาวกท าไดงาย ๆ ดงทเหนจากโปรแกรม ArrayStack.java ทเราเขยนขน Code ของ Stack ทใช array เปนตวเกบขอมล

1: /**

2: Stack using array to store data

3: accommodate any-type from user (almost)

4: */

5:

6: class ArrayStack<T> {

7: private int size;

8: private T[] stack;

9: private int top, numItems;

10:

11: //set size and allocate space for stack

12: public ArrayStack(int max) {

13: size = max; //set size of stack

14: stack = (T[])new Object[size]; //allocate space

15: top = -1; //no object yet

16: numItems = 0;

17: }

1 เราไมสามารถสราง array ส าหรบการเกบ generic ได ดงนนเราจงตองสราง stack ทใชเกบ Object กอน หลงจากนน

จง cast ใหเปน generic ดงทเหนในบรรทดท 14 อยางไรกตาม ถาเรา compile ดวย –Xlint:unchecked เราจะพบวา Java จะเตอนเราถงการใช cast ทอาจเกดปญหา (stack เปน Object[] แตเราบงคบใหเปน T[])

Top Operation Book 5

Book 4

Book 3

Book 2

Book 1

Pop

Book 5

Book 4

Book 3

Book 2

Book 1

Book 6 Top

Stack กอนการดง Book 6 ออก Stack หลงจากดง Book 6ออก

Book 6

Page 4: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

72

18:

19: //insert object onto stack

20: public void push(T obj) {

21: if(!full()) {

22: stack[++top] = obj;

23: numItems = top + 1;

24: }

25: else {

26: System.err.println("ERROR! Stack is full.");

27: System.exit(1);

28: }

29: }

30:

31: //remove object from stack

32: public T pop() {

33: if(empty())

34: return null;

35: return stack[top--];

36: }

37:

38: //check if stack is full

39: public boolean full() {

40: return (top == size-1);

41: }

42:

43: //check if stack is empty

44: public boolean empty() {

45: return (top == -1);

46: }

47:

48: public String toString() {

49: StringBuffer buf = new StringBuffer();

50: buf.append("top-> " + stack[top]);

51: for(int i = top-1; i >= 0; i--)

52: buf.append(", " + stack[i]);

53: return new String(buf);

54: }

55: }

การออกแบบ stack นนหลากหลายวธทเราสามารถท าได แตการออกแบบบางครงกตองค านงถงความเหมาะสม วาเราจะตองม method รองรบการท างานทงหมดหรอไม สวนไหนท user จะตองรบผดชอบเอง เชน การตรวจสอบและดกจบขอผดพลาดทอาจเกดข น ในการใสขอมลเขาส stack หรอการดงขอมลออกจาก code ขางบนน เราก าหนดใหม method full() และ method empty() ททงเราและ user สามารถเรยกใชได ดงจะเหนไดจาก method push() และ method pop() อกสาเหตหนงทเราตองตรวจสอบกเนองจากวา stack ของเราใช array เปนตวเกบขอมล และ array มการขอมลแบบจ ากด ท าใหไมสามารถเพมขอมลไดถา array เตม ลองมาทดสอบ code ทเราเขยนขนมาดวยโปรแกรมงาย ๆ น

1: /**

2: Testing stack that uses array as storage

3: */

4:

5: class ArrayStackTest {

6: public static void main(String []args) {

7: //create a stack holding 10 items

8: ArrayStack<Integer> stack = new ArrayStack<Integer>(10);

9:

10: //push 10 Integers onto stack

11: stack.push(45);

12: stack.push(5);

13: stack.push(32);

14: stack.push(78);

15: stack.push(12);

16: stack.push(99);

17: stack.push(27);

18: stack.push(19);

19: stack.push(66);

20: stack.push(7);

21:

22: System.out.println(stack); //display contents

Page 5: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

73

23:

24: //remove all Integers from stack

25: while(!stack.empty())

26: System.out.println("Pop " + stack.pop() +

" from Stack");

27: }

28: }

เราน าขอมลทเปน Object ชนด Integer ใสไวใน stack ของเราจนเตมทง 10 ตว หลงจากนนเราก pop ขอมลทงหมดออกจาก stack ดวยการใช while/loop (และ method empty() ในการตรวจสอบวา stack นนยงมขอมลอยอกหรอไม) ตวอยาง sample output top-> 7, 66, 19, 27, 99, 12, 78, 32, 5, 45

Pop 7 from Stack

Pop 66 from Stack

Pop 19 from Stack

Pop 27 from Stack

Pop 99 from Stack

Pop 12 from Stack

Pop 78 from Stack

Pop 32 from Stack

Pop 5 from Stack

Pop 45 from Stack

ผอานควรทดลองการน าขอมลเขา และดงขอมลออกจาก Stack ดวยขอมลตาง ๆ เพอใหเกดความเขาใจมากยงข น โปรแกรมตวอยางทตามมาเปนโปรแกรมตวอยางของการใช stack ในการจดการกบขอมลในรปแบบตาง ๆ 3.1.1.3 กำรใช stack ในกำร reverse String จากคณสมบตของ stack ทวา last-in, first-out ท าใหเราสามารถน า stack มาใชในการ reverse string ไดงาย ๆ ดงตวอยางทแสดงใหดน

1: /**

2: Using stack to reverse a string

3: */

4:

5: import static java.lang.System.out;

6:

7: class ReverseTest {

8: public static void main(String[] args) {

9: //if no input detect, exit with a message

10: if(args.length == 0) {

11: out.println("Usage: java

ReverseTest \"Your String\"");

12: System.exit(1);

13: }

14:

15: //calling reverse() with args[0] and display its result

16: out.println("Reversed string: " + reverse(args[0]));

17: }

18:

19: //reversing input string

20: public static String reverse(String input) {

21: String output = ""; //output string

22: int size = input.length(); //size of input string

23: ArrayStack<Character> stack = new ArrayStack<Character>(size);

24:

25: //pushing each character onto stack

26: for(int i = 0; i < input.length(); i++) {

27: char c = input.charAt(i); //get a char from string

28: stack.push(c); //push it onto stack

29: }

30:

31: //pop character from stack and put it in output

32: while(!stack.empty()) {

Page 6: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

74

33: char ch = stack.pop(); //pop character from stack

34: output += ch; //add character to output

35: }

36:

37: return output;

38: }

39: }

ขนตอนการท ากไมยาก เมอเราได string มาจาก keyboard แลวเรากท าการดงเอา character ออกจาก string ทละตว แลวน าไปใสไวใน stack เมอใสไวหมดแลวเรากจะม stack ทมขอมลดานบนเปน character ตวสดทายของ string ทอานเขามา ทนเมอเรา pop ขอมลออกจาก stack เรากจะไดขอมลตวสดทายของ string กอน และตวอน ๆ ถดไปจนกวาเราจะไดขอมลทงหมด ตวอยาง sample output D:\Stack>java ReverseTest "Java is Great!"

Reversed string: !taerG si avaJ

3.1.1.4 กำรเปลยนเลขฐำนสบใหเปนเลขฐำนสองดวยกำรใช stack stack สามารถทจะน ามาใชในการเปลยนเลขฐาน 10 ใหเปนเลขฐาน 2 ไดเปนอยางด วธการในการเปลยนเลขฐานสบใหเปนเลขฐานสองนน ใหเราน าสองไปหารเลขนน แลวเกบเศษทไดจากการหารนนใน stack หารไปเรอย ๆ จนหารไมได หลงจากนนเราก pop ขอมลทอยใน stack ออก ซงจะเปนเลขฐานสองของเลขฐานสบนน ดงโปรแกรมตวอยางทใหน

1: /**

2: converting positive number in base 10

3: to base 2 using stack

4: */

5:

6: import static java.lang.System.out;

7:

8: class Convert {

9: public static void main(String[] args) {

10: //if no input, exit with a message

11: if(args.length == 0) {

12: out.println("Usage: java Convert number");

13: System.exit(1);

14: }

15: ArrayStack<Integer> numStack = new ArrayStack<Integer>(20);

16: int remainder;

17: int number = Integer.parseInt(args[0]);

18:

19: //find remainder of number%2 and keep

20: //them on stack

21: while(number != 0) {

22: remainder = number % 2;

23: numStack.push(remainder);

24: number /= 2;

25: }

26:

27: //pop all digit from stack

28: out.print("Number in base two: ");

29: while(!numStack.empty()) {

30: out.print(numStack.pop());

31: }

32: }

33: }

ผลลพธของการ run โปรแกรมการเปลยนเลขฐานสบใหเปนเลขฐานสอง D:\codes\Stack>java Convert 400

Number in base two: 110010000

Page 7: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

75

3.1.1.5 กำรใช stack กบ Postfix-expression ในการประมวลผลสมการทางคณตศาสตร เชน 3 * ((4 – 2) * (5 + 4) + 3) (เราเรยกรปแบบการเขยนสมการนวา Infix notation) นน เราสามารถทจะน าเอา stack มาชวยได แตเราตองท าใหสมการมรปแบบทเออตอการประมวลผลทวาเสยกอน และรปแบบทชวยใหการน าเอา stack มาใชในการประมวลผลไดนนกคอ การเปลยนสมการใหอยในรปของ Postfix notation สมการทอยในรปแบบของ postfix จากตวอยางกอนหนานคอ 3 4 2 – 5 4 + * 3 + * ขนตอนในการประมวลผล postfix notation มดงนคอ

1. ถา input เปนตวเลข (digit) ใหเกบไวใน stack 2. ถา input เปนเครองหมายการประมวลผลให pop ขอมลออกจาก stack 2 ตว แลวจง

ท าการประมวลผลขอมลทงสอง เกบผลลพธไวใน stack 3. ท าขนตอน 1 และ 2 จนกวาจะหมดขอมล

ในการเขยนโปรแกรมเพอท าการประมวลผลสมการทอยในรปแบบของ postfix นนกอนอนเรา

ตองเปลยนสมการดงกลาวใหอยในรปแบบของ postfix กอน ซงสามารถท าไดดวยการใช stack เชนเดยวกน ซงมขนตอนการท างานดงน

1. ถา input เปนตวเลขใหเกบไวใน buffer 2. ถา input เปนเครองหมายประมวลผล ใหเกบไวใน stack 3. ถา input เปนเครองหมายวงเลบปด ใหดงเอาเครองหมายประมวลผลออกจาก stack

ไปเกบไวใน buffer (เราจะไมสนใจเครองหมายวงเลบเปด) 4. ท าขนตอนทงสามจนกวาจะหมดขอมล

ขนตอนการประมวลผลสมการ postfix ทใหน เราจะเนนการประมวลผลของสมการทใชวงเลบแบบเตมท (fully parenthesized expression) เชน ((( 3 + (2 + 5)) * ( 6 + 8 )) - ( 6 * 2 )) ตวอยางทเราไดแสดงใหดตอไปนใชไดเฉพาะสมการทมตวเลขเพยงแคตวเดยว (one digit) เทานน แตเราจะกลบมาพดถงการประมวลผล expression ทมตวเลขมากกวาหนงตวหลงจากน

//converts to postfix form

public static char[] infixToPostfix(char[] exp) {

ArrayStack<Character> s = new ArrayStack<Character>(exp.length);

StringBuffer buf = new StringBuffer();

for(int i = 0; i < exp.length; i++) {

if(exp[i] == ')')

buf.append(s.pop() + " ");

if(exp[i] == '+' || exp[i] == '-' || exp[i] == '*' || exp[i] == '/')

s.push(exp[i]);

if(exp[i] >= '0' && exp[i] <= '9')

buf.append(exp[i] + " ");

}

return new String(buf).toCharArray();

}

วธการในการเปลยนกไมยาก เราเพยงแคตรวจสอบดวาคาของ exp[i] มคาเปนอะไร ถาเปนเครองหมายของการประมวลผล (+, -, *, /) เรากจดเกบเครองหมายเหลานไวใน stack ถาเปนตวเลขเรากจะเกบตวเลขนไวใน buffer ถาเปนวงเลบเปดเรากจะไมท าอะไร แตถาเปนวงเลบปดเรากจะยายขอมลทอยดานบนของ stack (ซงตองเปนเครองหมายส าหรบการประมวลผลอยางแนนอน) ไปเกบไวใน buffer หลงจากนนเรากสง postfix นไปท าการประมวลผลตอไป //evaluates postfix form

public static Double evaluate(char[] exp) {

ArrayStack<Double> s = new ArrayStack<Double>(exp.length);

Double v1, v2;

for(int i = 0; i < exp.length; i++) {

Page 8: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

76

switch(exp[i]) {

case '+' : s.push(s.pop() + s.pop());

break;

case '-' : v1 = s.pop();

v2 = s.pop();

s.push(v2 - v1);

break;

case '*' : s.push(s.pop() * s.pop());

break;

case '/' : v1 = s.pop();

v2 = s.pop();

s.push(v2 / v1);

break;

}

//convert digit to int

while(exp[i] >= '0' && exp[i] <= '9')

s.push((double)(exp[i++] - '0'));

return s.pop();

}

ในการประมวลสมการทอยในรปของ postfix นนเมอเราเจอขอมลทเปนตวเลขเราจะเกบไวใน stack และเมอเราเจอเครองหมายของการประมวลผล เราจะท าการดงขอมลออกจาก stack 2 ตว แลวจงท าการประมวลผลขอมลสองตวนน พรอมทงเกบผลลพธทไดไวใน stack ส าหรบการประมวลทอาจตามมาตอไป โปรแกรม ArithmeticEvaluation.java รวบรวม code ส าหรบกระบวนการทงหมดทเกยวของกบการประมวลผลสมการในรปของ postfix หลงจากทเราไดท าการทดลองการประมวลผลดวยสมการ (2 * (((8 - 4) * (4 / 2)) + 2)) ขอมลทมอยใน stack เวลาตาง ๆ มดงน java ArithmeticEvaluation "(2 * (((8 - 4) * (4 / 2)) + 2))

Infix form: (2 * (((8 - 4) * (4 / 2)) + 2))

Postfix form: 2 8 4 - 4 2 / * 2 + *

top-> 2.0

top-> 8.0, 2.0

top-> 4.0, 8.0, 2.0

top-> 4.0, 2.0

top-> 4.0, 2.0

top-> 4.0, 4.0, 2.0

top-> 2.0, 4.0, 4.0, 2.0

top-> 2.0, 4.0, 2.0

top-> 2.0, 4.0, 2.0

top-> 8.0, 2.0

top-> 8.0, 2.0

top-> 2.0, 8.0, 2.0

top-> 10.0, 2.0

top-> 10.0, 2.0

top-> 20.0

top-> 20.0

Result: 20.00

และโปรแกรมการท างานทงหมดของการประมวลผลสมการทอยในรปแบบของ postfix มดงน

1: /**

2: Evaluating arithmetic expressions using stack

3: work only for one digit input with no error detecting!

4: */

5:

6: import static java.lang.System.out;

7:

8: class ArithmeticEvaluation {

9: public static void main(String[] args) {

10: if(args.length == 0) {

11: out.println("Usage: ArithmeticEvaluation \"expression\"");

12: out.println("e.g. \"(3 * (2 - 4 ) * (4 / (5 - 2)))\"");

13: System.exit(1);

14: }

15: char []exp = args[0].toCharArray();

16: exp = infixToPostfix(exp);

ขอมลใน stack ณ เวลาตาง ๆ ของการประมวลผล

Page 9: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

77

17: out.printf("Result: %.2f%n", evaluate(exp));

18: }

19:

20: //converts to postfix form

21: public static char[] infixToPostfix(char[] exp) {

22: System.out.println("Infix form: " + new String(exp));

23: ArrayStack<Character> s = new ArrayStack<Character>(exp.length);

24: StringBuffer buf = new StringBuffer();

25: for(int i = 0; i < exp.length; i++) {

26: if(exp[i] == ')')

27: buf.append(s.pop() + " ");

28: if(exp[i] == '+' || exp[i] == '-' ||

29: exp[i] == '*' || exp[i] == '/')

30: s.push(exp[i]);

31: if(exp[i] >= '0' && exp[i] <= '9')

32: buf.append(exp[i] + " ");

33: }

34: return new String(buf).toCharArray();

35: }

36:

37: //evaluates postfix form

38: public static Double evaluate(char[] exp) {

39: System.out.println("Postfix form: " + new String(exp));

40: ArrayStack<Double> s = New ArrayStack<Double>(exp.length);

41: Double v1, v2;

42: for(int i = 0; i < exp.length; i++) {

43: switch(exp[i]) {

44: case '+' : s.push(s.pop() + s.pop());

45: break;

46: case '-' : v1 = s.pop();

47: v2 = s.pop();

48: s.push(v2 - v1);

49: break;

50: case '*' : s.push(s.pop() * s.pop());

51: break;

52: case '/' : v1 = s.pop();

53: v2 = s.pop();

54: s.push(v2 / v1);

55: break;

56: }

57:

58: //convert digit to int

59: while(exp[i] >= '0' && exp[i] <= '9')

60: s.push((double)(exp[i++] - '0'));

61: }

62: return s.pop();

63: }

64: }

ตวอยางของผลลพธทไดจากการ run ดวยสมการ (5 * (((9 + 8) * (4 * 6)) + 7)) คอ Infix form: (5 * (((9 + 8) * (4 * 6)) + 7))

Postfix form: 5 9 8 + 4 6 * * 7 + *

Result: 2075.00

กระบวนการในการประมวลผลสมการทมตวเลขมากกวา 1 digit นน เราเพยงแคเปลยนการอานสมการจากทเคยอานเปนทละตวอกษร เรากอานเปนทละหนวย (หรอทเรยกงาย ๆ วาทละค า – token) ซงท าไดงาย ๆ ดวยการใช class StringTokenizer ดงตวอยางทแสดงใหดน public static Double evaluate(String exp) {

System.out.println("Postfix form: " + new String(exp));

StringTokenizer str = new StringTokenizer(exp);

ArrayStack<Double> st = new ArrayStack<Double>(str.countTokens());

String token;

Double v1, v2, result = 0.0D;

//until all tokens have been processed

while(str.hasMoreTokens()) {

token = str.nextToken();

//token is an operator, we pop 2 operands and perform

//operation on them - push result back onto stack

Page 10: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

78

if(isOperator(token)) {

v2 = st.pop();

v1 = st.pop();

result = operate(token.charAt(0), v1, v2);

st.push(result);

}

//token is an operand, we push it onto stack

else

st.push(new Double(Double.parseDouble(token)));

//print content of stack during the operation

System.out.println(st);

}

return result;

}

เราไดดดแปลง method evaluate() ของเรา ใหรบ String แทน char[] ซงเราไดสง String ตวน (exp) ไปให StringTokenizer() ท าการอานพรอมกบแปลงรปแบบของ exp ใหอยในรปแบบท StringTokenizer ตองการ ซงเราไดเกบไวในตวแปร str หลงจากนนเรากสราง stack ส าหรบเกบ token ทเราจะดงออกมาจาก str ขนตอนตาง ๆ ทเหลออยกเหมอนกบโปรแกรม ArithmeticEvaluation.java ทเราเขยนไวกอนหนาน เพยงแตเราไดจดกระบวนการประมวลผลใหอยในรปแบบของ method เพอใหดงายขน

และ method ทเราเขยนขนใหมคอ private static boolean isOperator(String token) {

return (token.equals("+") || token.equals("-") ||

token.equals("*") || token.equals("/"));

}

private static Double operate(char op, Double v1, Double v2) {

Double result = 0.0D;

switch(op) {

case '+' : result = v1 + v2;

break;

case '-' : result = v1 - v2;

break;

case '*' : result = v1 * v2;

break;

case '/' : result = v1 / v2;

break;

}

return result;

}

Method ทส าคญอกตวหนงกคอ infixToPostfix() ซงเราตองดดแปลงใหรองรบการประมวลผลของเรา นนกคอ ตวเลขทใสตามกนมาจะตองถกเกบใหเปนหนง token เชน สมมตวาเราใส 2 * 34 เราตองมนใจวา 34 มคาเปน 1 token (ไมใช 2 token คอ 3 กบ 4) public static String infixToPostfix(char[] exp) {

System.out.println("Infix form: " + new String(exp));

ArrayStack<Character> s = new

ArrayStack<Character>(exp.length);

StringBuffer buf = new StringBuffer();

for(int i = 0; i < exp.length; i++) {

if(exp[i] == ')')

buf.append(" " + s.pop() + " ");

if(exp[i] == '+' || exp[i] == '-' ||

exp[i] == '*' || exp[i] == '/')

s.push(exp[i]);

if(exp[i] >= '0' && exp[i] <= '9')

buf.append(exp[i]);

if(exp[i] == ' ') buf.append(" ");

}

return new String(buf);

}

Page 11: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

79

Code ทอยในกรอบและตวหนาคอสวนทเราไดท าการเปลยนเพอรองรบตวเลขทมมากกวาหนง digit สาเหตทเราท าแบบนกเพราะวา StringTokenizer จะอานขอมลทอยใน string ทละค า (ข นอยกบ delimiter ใน string นน ๆ ซงในทน delimiter ทใชเปนคา default คอ ชองวาง) ดงนนเราจงตองใสชองวางหลงจากทเราดง operator ออกจาก stack และเมอเราเจอชองวางใน string code ทงหมดกมดงน

1: /**

2: Evaluating arithmetic expressions using stack

3: Expression must be fully parenthesized e.g.

4: ((( 3 + (2 + 5)) * ( 6 + 8 )) - ( 6 * 2 ))

5: This version allows more than one digit & no error checking

6: */

7:

8: import static java.lang.System.out;

9: import java.util.StringTokenizer;

10: import java.util.Scanner;

11:

12: class ArithmeticEvaluation2 {

13: public static void main(String[] args) {

14: out.println("Enter infix expression: ");

15: out.print("e.g. \"(((3 + (2 + 5)) * (6 + 8)) - (6 * 2))\" : ");

16: Scanner in = new Scanner(System.in);

17: String exp = in.nextLine();

18:

19: exp = infixToPostfix(exp.toCharArray());

20: out.printf("Result: %.2f%n", evaluate(exp));

21: }

22:

23: //converts to postfix form

24: public static String infixToPostfix(char[] exp) {

25: System.out.println("Infix form: " + new String(exp));

26: ArrayStack<Character> s = new ArrayStack<Character>(exp.length);

27: StringBuffer buf = new StringBuffer();

28: for(int i = 0; i < exp.length; i++) {

29: if(exp[i] == ')')

30: buf.append(" " + s.pop() + " ");

31: if(exp[i] == '+' || exp[i] == '-' ||

exp[i] == '*' || exp[i] == '/')

32: s.push(exp[i]);

33: if(exp[i] >= '0' && exp[i] <= '9')

34: buf.append(exp[i]);

35: if(exp[i] == ' ') buf.append(" ");

36: }

37: return new String(buf);

38: }

39:

40: //evaluates postfix form

41: public static Double evaluate(String exp) {

42: System.out.println("Postfix form: " + new String(exp));

43: StringTokenizer str = new StringTokenizer(exp);

44: ArrayStack<Double> st = new ArrayStack<Double>(str.countTokens());

45: String token;

46: Double v1, v2, result = 0.0D;

47:

48: //until all tokens have been processed

49: while(str.hasMoreTokens()) {

50: token = str.nextToken();

51: //token is an operator, we pop 2 operands and

52: //perform operation on them - push result onto stack

53: if(isOperator(token)) {

54: v2 = st.pop();

55: v1 = st.pop();

56: result = operate(token.charAt(0), v1, v2);

57: st.push(result);

58: }

59: //token is an operand, we push it onto stack

60: else

61: st.push(new Double(Double.parseDouble(token)));

62:

Page 12: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

80

63: //print content of stack during the operation

64: System.out.println(st);

65: }

66: return result;

67: }

68:

69: //determines if the token is an operator

70: private static boolean isOperator(String token) {

71: return (token.equals("+") || token.equals("-") ||

72: token.equals("*") || token.equals("/"));

73: }

74:

75: //evaluates two oeprands with a given operator

76: private static Double operate(char op, Double v1, Double v2) {

77: Double result = 0.0D;

78: switch(op) {

79: case '+' : result = v1 + v2;

80: break;

81: case '-' : result = v1 - v2;

82: break;

83: case '*' : result = v1 * v2;

84: break;

85: case '/' : result = v1 / v2;

86: break;

87: }

88: return result;

89: }

90: }

เมอทดสอบดวยสมการ (((30 + (20 + 50)) * (60 + 80)) - (60 * 20)) ผลลพธทเราไดคอ Infix form: (((30 + (20 + 50)) * (60 + 80)) - (60 * 20))

Postfix form: 30 20 50 + + 60 80 + * 60 20 * -

top-> 30.0

top-> 20.0, 30.0

top-> 50.0, 20.0, 30.0

top-> 70.0, 30.0

top-> 100.0

top-> 60.0, 100.0

top-> 80.0, 60.0, 100.0

top-> 140.0, 100.0

top-> 14000.0

top-> 60.0, 14000.0

top-> 20.0, 60.0, 14000.0

top-> 1200.0, 14000.0

top-> 12800.0

Result: 12800.00

3.1.2 Stack ทไมมขอจ ำกดในเรองของขนำด เราไดดตวอยางการใช array ทมความจ ากดในเรองของขนาดเปนโครงสรางหลกของ Stack มาพอสมควร ตอไปเราจะมาดตวอยางการออกแบบ Stack ทใช Dynamic array เปนโครงสรางหลกในการเกบขอมล เนองจากวาเราไมมขอจ ากดในเรองของจ านวนของขอมลทสามารถเกบไดใน Stack ดงนน ในการน าขอมลเขาเราจงไมตองตรวจสอบวา Stack ของเราจะเตมหรอไม (ในมมมองของผใช Stack ของเรา) เพยงแตเราตองมาเพมขนาดความจใหกบ array ของเราถา array นนไมสามารถรองรบการน าเขาขอมลใหมได เรามาเรมดวยการด class DynamicArrayStack กอน หลงจากนน เราจะมาดกนถง method ตาง ๆ ทมอยใน class น

1: /**

2: Use dynamic array to store objects

3: */

4:

5: import java.lang.reflect.Array;

6:

7: class DynamicArrayStack<T> {

8: private T[] stack;

9: private int top, numItems;

Page 13: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

81

10: static final int INITIAL_CAPACITY = 10;

11:

12: //creating a stack with initial capacity of 10 objects

13: DynamicArrayStack() {

14: stack = (T[])new Object[INITIAL_CAPACITY];

15: top = -1;

16: numItems = 0;

17: }

18:

19: //insert object onto stack and

20: //increment number of objects in the stack

21: public void push(T item) {

22: //if exceeds the initial capacity, double the size

23: if(top == stack.length - 1) {

24: T[] newStack = (T[])doubleCapacity(stack);

25: stack = newStack;

26: }

27: stack[++top] = item; //pushing object

28: numItems = top + 1; //number of items so far

29: }

30:

31: //remove currently inserted object from the stack

32: public T pop() {

33: //if our stack is empty, returns null

34: if(empty())

35: return null;

36: //otherwise, decrements size and returns the object

37: --numItems;

38: return stack[top--];

39: }

40:

41: //internal method to verify if stack is empty

42: private boolean empty() {

43: return (top == -1);

44: }

45:

46: //internal method to double the size of stack

47: private T[] doubleCapacity(T[] source) {

48: int sourceLength = Array.getLength(source);

49: Class arrayClass = source.getClass();

50: Class componentClass = arrayClass.getComponentType();

51: T[] result = (T[])Array.newInstance(componentClass,

sourceLength * 2);

52: System.arraycopy(source, 0, result, 0, sourceLength);

53: return result;

54: }

55:

56: //display items in stack via System.out.println()

57: public String toString() {

58: StringBuffer buf = new StringBuffer();

59: buf.append("top -> " + stack[numItems-1]);

60: for(int i = numItems-2; i >= 0; i--)

61: buf.append(", " + stack[i]);

62: return new String(buf);

63: }

64: }

Method ทส าคญส าหรบการออกแบบโครงสรางของ Stack ทขยายขนาดของความจเองเมอมความจ าเปนนนมอยหลก ๆ คอ ตว constructor ทใชในการสราง Stack ครงแรก, method push(), และ method doubleCapacity() พรอมกนนเรายงไดสราง toString() ขนมาใชส าหรบการสงขอมลทอยใน Stack ไปยงชองทางการสงขอมลออกมาตรฐาน (standard output) กอนอนเรามาดถงตว constructor DynamicArrayStack() {

stack = (T[])new Object[INITIAL_CAPACITY];

top = -1;

numItems = 0;

}

Page 14: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

82

เราก าหนดใหขนาดของความจเบองตนของ Stack มคาเปน 10 พรอมทงก าหนดใหตวแปร numItems เปนทเกบจ านวนของ object ทมอยจรง ณ เวลานน (ซงเราใชตวแปรนในการแสดงผลผานทางชองทางการสงขอมลออกมาตรฐาน) ใน push() นนกอนทเราจะน าขอมลเขา เราตรวจสอบดกอนวาเราตองขยายขนาดความจหรอไม ถาตองขยายเรากเรยกใช doubleCapacity() ในการเพมขนาดใหเปนสองเทา (ผอานสามารถก าหนดใหเปนเทาไรกได ถาตองการ) public void push(T item) {

//if exceeds the initial capacity, double the size

if(top == stack.length - 1) {

T[] newStack = (T[])doubleCapacity(stack);

stack = newStack;

}

stack[++top] = item; //pushing object

numItems = top + 1; //number of items so far

}

ในสวนของ doubleCapacity() นนเราไดน ามาจากโปรแกรม DynamicArray.java ในบททหนง หากผอานจ าไมไดควรกลบไปทบทวนดใหม สวน toString() นนกเขยนขนงาย ๆ โดยก าหนดให มการบอกต าแหนงของ top วาอยสวนไหนของการแสดงผล public String toString() {

StringBuffer buf = new StringBuffer();

buf.append("top -> " + stack[numItems-1]);

for(int i = numItems-2; i >= 0; i--)

buf.append(", " + stack[i]);

return new String(buf);

}

หลงจากททดลองดวยโปรแกรม TestDynamicArrayStack.java ดงทเหนดานลางน

1: /**

2: Testing dynamic stack

3: */

4:

5: class TestDynamicArrayStack {

6: public static void main(String[] args) {

7: //create stack

8: DynamicArrayStack<Integer> stack = new DynamicArrayStack<Integer>();

9:

10: //create 15 random Integer objects

11: //and insert them onto stack

12: for(int i = 0; i < 15; i++) {

13: int data = (int)(Math.random() * 100 + 1);

14: stack.push(data);

15: }

16: System.out.println(stack); //display contents of stack

17:

18: //remove 8 objects from stack

19: for(int i = 0; i < 8; i++) {

20: stack.pop();

21: }

22: System.out.println(stack); //display contents again

23: }

24: }

ผลลพธทไดคอ

top -> 30, 92, 51, 35, 94, 85, 76, 55, 18, 33, 25, 2, 42, 70, 47

top -> 18, 33, 25, 2, 42, 70, 47

เราน าขอมลทเปน Integer ใสเขาส Stack จ านวน 15 ตวเพอแสดงใหเหนวา Stack ของเราขยายความจใหเราโดยอตโนมต (เรารวาความจเรมตนของเรามคาเปน 10) หลงจากนนเรากแสดงผลผานทาง standard output เราท าการลบขอมลออก 8 ตวพรอมกบแสดงผลของขอมลทเหลออยใน Stack เพอยนยนวาการท างานของ Stack นนถกตอง

Page 15: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

83

ผอานจะเหนวาโครงสรางของ Stack ทเราสรางขนใหมนนท างานรองรบการน าเขาไดดกวาทเราไดออกแบบไวกอนหนาน เราไมตองกงวลถงความจทจ ากดของ Stack อกตอไป อยางไรกตามโครงสรางของ Stack ทเราไดออกแบบไวยงมอกหลายสวนทสามารถน าไปปรบปรงเพอใหการใชงานท าไดงายขน เชน ในการ pop ขอมลออกจาก Stack นนเรายงตองท าการ cast ใหอยในรปของ object ทเราไดก าหนดไว คงจะเปนส งทดถาเราสามารถทจะรองรบการน าขอมลเขา และออกจาก Stack โดยไมตองท าการ cast หรอกงวลกบชนดของขอมลทเราก าลงท าอย 3.2 Queue Queue เปนโครงสรางทเกบขอมลในรปแบบทเรยกวา First In, First Out (เขากอน – ออกกอน) หรอ FIFO queue มาจากภาษาองกฤษทแปลวา การจดอนดบ หรอ การจดแถว ดงทแสดงในภาพท 3.4

ภาพท 3.4 การเขาแถวเพอรอรบการบรการ

queue ทเราจะเขยนขนกจะยงคงใช array เปนตวเกบขอมล แตเราจะใช array ทน าเอาเนอททวางลงเมอมการดงขอมลออกไปกลบมาใชใหม วธนจะท าใหเรามท ทสามารถจะจดเกบขอมลได ดกวา array แบบปกต เราเรยก array แบบนวา circular array ผอานอาจใช array ธรรมดาใน

การเกบขอมลกได แตการบรหารและจดการกบเนอทมปญหามากกวาการจดเกบดวย circular array กลาวคอเมอมการน าขอมลเขา เราจะน าไปใสไวท rear และเลอนไปอกหนงต าแหนง และเมอดงออกเรากดงออกจากทาง front และกเลอนไปอกหนงต าแหนง วธการแบบนท าใหเราเสยเนอททางดานหนาของ array เมอเราดงขอมลออก ดงทแสดงในภาพท 3.5 น

ภาพท 3.5 การสญเสยเนอทจากการดงขอมลออก

เนองจาก queue เปนโครงสรางทน าขอมลเขาส queue ทางดานหลงและดงขอมลออกทาง

ดานหนา ดงนนการเขยน code จะตองจ าต าแหนงของขอมลทงทอยดานหนาและดานหลงของ queue อกส งหนงทเราจะตองค านงถงกคอ การตรวจสอบวา queue เตม (full) หรอวาง (empty) เนองจาก circular queue น าเอาชองวางทเหลออยมาใช ดงนนการตรวจสอบจงตองใช index 2 ตวเปนตวชวย เราใช front และ rear เปน index ทอยดานหนาและดานหลงของ queue ตามล าดบ เราตรวจสอบวา queue วาง (empty) ดวยประโยค

(front == rear)

หนา (front) หลง (rear)

Queue of Java cups

55 78 12 7 85 23 77 235

front rear

เนอทสญเสยหลงจากการดงขอมลออก

Page 16: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

84

และ queue เตมดวยประโยค (rear + 1) % size == front

เรามาลองดภาพตวอยางสถานการณทงสองทไดกลาวมาแลว ภาพแรกเปนสถานะของ queue ในขณะทไมมขอมลอย

ภาพท 3.6 สถานะภาพขณะท queue ยงไมมขอมล

เนองจากวาเราใชการค านวณดวย (rear + 1) % size == front เปนตวตรวจสอบความจเตมของ queue ดงนนเราจะเสยชองวางไปหนงท ดงทแสดงในภาพท 3.7

ภาพท 3.7 ชองวางทเสยไปในขณะท queue เตม

สมมตวามการดงขอมลออกจาก queue 2 ตวหลงจากท queue เตม เรากน าชองวางท rear ช

อยมาใช พรอมทงท าการก าหนดต าแหนงของ rear ใหมใหรองรบการใสขอมลดวยการวนกลบของ rear ดงทแสดงใหดในภาพท 3.8

0 1 2 3 4

front

rear

ในการสราง queue ครงแรก เราก าหนดให front และ rear ชไปทต าแหนงเดยวกนคอ 0 และเราจะเลอน rear ทกครงทมการน าขอมลเขาส queue

หลงจากทเราใสขอมลเขาส queue 4 ตวเรากจะ

ไดภาพดงทเหน ซงเปนสถานะภาพของ queue ทเตม คอ (rear + 1) % size == front [(4 + 1) % 5 == 0] จะเหนวาเราเสยชองวางไปหนงชองวาง ซงเปนหนงในวธทเราเลอกใชในการ

ออกแบบโครงสราง queue ของเรา

45 89 23 10

0 1 2 3 4

front rear

Page 17: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

85

ภาพท 3.8 การน าชองวางกลบมาใชใหม และการก าหนด rear ดวยการวนกลบ

อยางไรกตามถาสงเกตใหดจะเหนวา ถาเราใหผใชก าหนดขนาดของ queue ใหเปน n โดยท n เปนคา integer ทเปนบวก queue ของเราจะสามารถเกบขอมลไดสงสดไดเพยง n – 1 ตว (เชนทแสดงใหดในภาพกอนหนาน) เพราะฉะนนถาเราอยากใหการก าหนดคาของผใชเปนจรงดงทเขาก าหนดเรากเพยงแตเพมขนาด (size) ของ queue ใหมคาเกนไปหนงคา ดงทแสดงไวใน constructor ของ QueueArray (size = max + 1) ในบางครงเราอาจเพมตวแปรอกตวหนง (count) เพอเปนตวบอกวามขอมลอยใน queue กตว และการเพมตวแปรตวนอาจชวยใหการเขยน code ของการท างานของ queue เขยนไดงายขน โปรแกรมตวอยางของเราใชตวแปร count ในการแสดงผลมากกวาทจะใชท าอยางอน ดงทแสดงไวใน constructor ทเหนน public QueueArray(int max) {

size = max + 1; //making size one size bigger

queue = new Object[size]; //to deal with wrap around

front = rear = 0; //initial queue: empty

count = 0; //no object in queue

}

ในทางปฏบตนนเมอ front และ rear มาอยในต าแหนงทอยถดกน การตรวจสอบวา queue เตมนนจะท าใหการ insert ขอมลตวสดทายเปนไปไมได เพราะวาประโยค if((rear + 1) % size == front)

จะท าใหเราเสยชองวางใน queue ไปหนงชองดงทไดกลาวมาแลว แตเพอใหผใชมความรสกวาไดใช queue อยางทเขาก าหนดไว (โดยไมรวาการใชเนอทในหนวยความจ านนมการใชเกน) เราจงตองเพมขนาดของการใชภายใน queue มากกวาการจองใชจรงจากผใช 3.2.1 กำรน ำขอมลเขำส queue

การ insert ขอมลเขาส queue ของเรากท าไดดวยการตรวจสอบวา queue ของเรานน เตมหรอยงดวยการเรยก method full() ถายงไมเตมกใสเขาไปและเลอน rear pointer ไปอกหนงชองดวยการใชค าสง rear = (rear + 1) % size; //move rear pointer

ซงค าสงนจะท าการหา index ทวางอยถดไปจาก index ตวเดมดวยการใชการหารของ integer หรอทเราเรยกวา modular (หรอ modulo) operation

1 0 2 4 3

45 89 23 10

0 1 2 3 4

front rear

45 89 99 23 10

front rear

หลงจากทเราดงขอมลออก 2 ตว front กจะมาช

ในต าแหนง index = 2 ซงท าใหการตรวจสอบวา queue เตมเปน false [(4 + 1) % 5 == 2] false ดงนนเราจงน าขอมล 99 ใส ณ

ต าแหนงท rear = 4 ชอยพรอมทงท าการเลอน rear ดวยประโยค rear = (rear + 1) % size ดงนน rear จงไปชท 0 ซงเปนต าแหนงแรกของ array ทเราน ากลบมาใชใหม

อยางไรกตามถาเราใสขอมลอกตว rear กจะมาช

ท index = 1 ซงจะท าใหประโยคของการตรวจสอบวา queue เตมเปนจรง เรากยงคงเสยชองวางอกหนงชองเหมอนเดม

วาง 2 ชอง

Page 18: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

86

public void insert(T obj) {

//exit routine if queue is full

if(full()) {

System.err.println("Error: queue is FULL!");

System.exit(1);

}

queue[rear] = obj; //insert object

rear = (rear + 1) % size; //move rear pointer

count++; //one more object added

}

3.2.2 กำรดงขอมลออกจำก queue การ remove ขอมลออกจาก queue กท าคลาย ๆ กบการ insert เพยงแตแทนทเราจะท ากบ

rear pointer เรากมาท ากบ front pointer เมอเราดงขอมลออกแลว (เกบไวในทเกบชวคราว) เรากตองเลอน front pointer ของเราใหอยในททเหมาะสม ดวยการใชค าสง front = (front + 1) % size; //move front pointer

ซงถาดแลวมนกคอค าสงเดยวกนกบการเลอน rear pointer เราเพยงแตมาท ากบ front pointer เทานน public T remove() {

//exit routine if queue is empty

if(empty()) {

System.err.println("Error: queue is EMPTY!");

System.exit(2);

}

T temp = queue[front]; //remove object

queue[front] = null; //set queue[front] to null

front = (front + 1) % size; //move front pointer

count--; //one object less

return temp; //return removed object

}

Method ตวอน ๆ กไมยากทจะท าความเขาใจ เราเพยงแตตองรวา queue ของเราจะ empty ถา front และ rear pointer มาอยในต าแหนงเดยวกน และ queue จะเตมเมอทงสอง pointer อยถดกนหนงต าแหนง Code ของ QueueArray

1: /**

2: Queue using array to store data

3: */

4:

5: class QueueArray<T> {

6: private int size; //size of queue

7: private int count; //# of objects in queue

8: private T[] queue; //space for objects

9: private int front, rear; //front and rear pointers

10:

11: public QueueArray(int max) {

12: size = max + 1; //one size bigger

13: queue = (T[])new Object[size];

14: front = rear = 0; //initial queue: empty

15: count = 0; //no object in queue

16: }

17:

18: //insert object into queue

19: public void insert(T obj) {

20: //exit routine if queue is full

21: if(full()) {

22: System.err.println("Error: queue is FULL!");

23: System.exit(1);

24: }

25: queue[rear] = obj; //insert object

26: rear = (rear + 1) % size; //move rear pointer

27: count++; //one more object added

28: }

Page 19: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

87

29:

30: //remove object from array

31: public T remove() {

32: //exit routine if queue is empty

33: if(empty()) {

34: System.err.println("Error: queue is EMPTY!");

35: System.exit(2);

36: }

37: T temp = queue[front]; //remove object

38: queue[front] = null; //set queue[front] to null

39: front = (front + 1) % size; //move front pointer

40: count--; //one object less

41: return temp; //return removed object

42: }

43:

44: //when rear pointer is right next to front pointer

45: private boolean full() {

46: if((rear + 1) % size == front)

47: return true;

48: else

49: return false;

50: }

51:

52: //when rear is at the same position as front

53: private boolean empty() {

54: if(rear == front)

55: return true;

56: else

57: return false;

58: }

59:

60: //display queue's content

61: public void printQ() {

62: System.out.print("(" + queue[0]);

63: for(int i = 1; i < queue.length; i++)

64: System.out.print(", " + queue[i]);

65: System.out.println(")");

66: }

67:

68: //count empty spaces

69: public int emptySpaces() {

70: return size - count - 1;

71: }

72: }

หลงจากททดลอง run ดดวยโปรแกรมทเหนน

1: /**

2: Testing module for queue

3: */

4:

5: import static java.lang.System.out;

6:

7: class TestQueueArray {

8: public static void main(String[] args) {

9: QueueArray<Integer> queue = new QueueArray<Integer>(10);

10:

11: //insert random Integers into queue

12: out.println("Insert 10 items into queue");

13: for(int i = 0; i < 10; i++) {

14: int object = (int)(Math.random() * 10);

15: queue.insert(object);

16: queue.printQ(); //for viewing purpose only

17: }

18: out.print("Queue after insertion: ");

19: queue.printQ();

20: out.println("Spaces left = " + queue.emptySpaces());

21:

22: //remove 5 objects from queue

23: out.println("\nRemove 5 items from queue");

24: for(int j = 0; j < 5; j++) {

25: Integer object = (Integer)queue.remove();

26: queue.printQ(); //for viewing purpose only

Page 20: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

88

27: }

28: out.print("Queue after removal: ");

29: queue.printQ();

30: out.println("Spaces left = " + queue.emptySpaces());

31:

32: //insert 4 more random Integers into queue

33: out.println("\nInsert 4 items into queue");

34: for(int i = 0; i < 4; i++) {

35: Integer object = new Integer((int)(Math.random() * 10));

36: queue.insert(object);

37: queue.printQ(); //for viewing purpose only

38: }

39: out.print("Queue after insertion: ");

40: queue.printQ();

41: out.println("Spaces left = " + queue.emptySpaces());

42: }

43: }

ผลลพธดงทไดคอ (เราแสดงผลจ านวนความจของ array ทเปนอยจรง - มากกวาการใชงานจรงหนงต าแหนง) Insert 10 items into queue

(8, null, null, null, null, null, null, null, null, null, null)

(8, 9, null, null, null, null, null, null, null, null, null)

(8, 9, 4, null, null, null, null, null, null, null, null)

(8, 9, 4, 0, null, null, null, null, null, null, null)

(8, 9, 4, 0, 1, null, null, null, null, null, null)

(8, 9, 4, 0, 1, 0, null, null, null, null, null)

(8, 9, 4, 0, 1, 0, 5, null, null, null, null)

(8, 9, 4, 0, 1, 0, 5, 6, null, null, null)

(8, 9, 4, 0, 1, 0, 5, 6, 5, null, null)

(8, 9, 4, 0, 1, 0, 5, 6, 5, 0, null)

Queue after insertion: (8, 9, 4, 0, 1, 0, 5, 6, 5, 0, null)

Spaces left = 0

Remove 5 items from queue

(null, 9, 4, 0, 1, 0, 5, 6, 5, 0, null)

(null, null, 4, 0, 1, 0, 5, 6, 5, 0, null)

(null, null, null, 0, 1, 0, 5, 6, 5, 0, null)

(null, null, null, null, 1, 0, 5, 6, 5, 0, null)

(null, null, null, null, null, 0, 5, 6, 5, 0, null)

Queue after removal: (null, null, null, null, null, 0, 5, 6, 5, 0, null)

Spaces left = 5

Insert 4 items into queue

(null, null, null, null, null, 0, 5, 6, 5, 0, 0)

(7, null, null, null, null, 0, 5, 6, 5, 0, 0)

(7, 3, null, null, null, 0, 5, 6, 5, 0, 0)

(7, 3, 3, null, null, 0, 5, 6, 5, 0, 0)

Queue after insertion: (7, 3, 3, null, null, 0, 5, 6, 5, 0, 0)

Spaces left = 1

เราใช printQ() เปนตวแสดงผลขอมลทกตวทอยใน queue เพอใหผอานมองเหนถงต าแหนงชองวางทเกดข นเมอมการน าขอมลเขา และการดงขอมลออก แตถาตองการแสดงผลเฉพาะขอมลตามทก าหนดไวดวยขนาดความจของ queue เราตองเขยน method ขนมาใหม (ด method toString() ในเรองของ Priority queue) 3.2.3 Priority Queue Queue ทเราเขยนขนยงเปน queue ทใชกนอยโดยทวไป ยงม queue อยอกหลายแบบทมการจดเกบขอมลแตกตางออกไป เชน priority queue ซงเปน queue ทใชในระบบปฏบตการในแบบ multitasking ในการเกบขอมลของ queue แบบนจะตองมการจดเกบตาม priority ทได ก าหนดไว ซงอาจเปนเงอนไขใด ๆ กไดทท าใหขอมลใน queue มการจดเกบแบบม order เชน ใหขอมลทมคานอยทสดเปนขอมลทม priority สงสดและการจดเกบกจดเกบแบบมากไปหานอย เราก าหนดใหการจดเกบขอมลมการเรยงจากมากไปหานอย เพราะฉะนนเรากไมจ าเปนทจะตองก าหนดใหม front และ rear ส าหรบการบอกต าแหนงทตองน าขอมลเขา และดงขอมลออก เราร วาขอมล ณ ต าแหนง index = 0 คอขอมลทม priority ต าทสด และขอมล ณ ต าแหนงทายสด

Page 21: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

89

คอ ขอมลทม priority สงสด ดงนนการดงออกกเพยงแตสงคา ณ ต าแหนงทายสด สวนการน าขอมลเขานนจะตองหาต าแหนงทเหมาะสมใหเจอ กอนทจะมการใสขอมล ณ ต าแหนงทหาเจอ ดงทแสดงในภาพท 3.8

ภาพท 3.8 ต าแหนงของขอมลทม Priority ต าสด / สงสด และการน าขอมลเขา

ตวอยางของ class PriorityQ ทเราไดสรางขน

1: /**

2: Priority Queue using array + smallest key has high priority

3: */

4:

5: class PriorityQ<T> {

6: private int size, elems;

7: private T[] que;

8:

9: PriorityQ(int max) {

10: size = max;

11: elems = 0;

12: que = (T[])new Object[size];

13: }

14:

15: //insert object into que in descending order

16: public void insert(T value) {

17: int i;

18: for(i = 0; i < elems; i++) {

19: if(((Comparable)que[i]).compareTo(value) < 0)

20: break;

21: }

22: //shift positions

23: for(int j = elems; j > i; j--)

24: que[j] = que[j - 1];

25: //insert element

26: que[i] = value;

27: elems++;

28: }

29:

30: //remove item from queue

31: public T remove() {

32: return que[--elems];

33: }

34:

35: //display contents via System.out.println()

36: public String toString() {

37: StringBuffer buf = new StringBuffer();

38: buf.append("rear->(" + que[0]);

39: for(int i = 1; i < elems; i++)

40: buf.append(", " + que[i]);

41: return new String(buf + ")<-front");

42: }

43: }

4 3 2 1 0

55

ขอมลทม Priority นอย

ทสด 42

ต าแหนงของ 42

ขยบขอมล 2 ตวนออก

ขอมลทม Priority

สงทสด

50 44 35 33

Page 22: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

90

เราคงไมตองอธบายมากมายนกในเรองของ code ทใหดานบนน ผอานไดสมผสกบการน าขอมลเขาแบบจดเรยงมากอนหนานแลว สวนการน าขอมลออกนน เราใชค าสง return que[--elems];

ซงท าหนาทลดคาของ index ของ array ลงกอนหนงคา กอนทจะสงกลบออกไปใหผเรยก หลงจากท run ดวยโปรแกรม TestPriorityQ.java ทใหน

1: /**

2: Testing priority queue

3: */

4:

5: import static java.lang.System.out;

6:

7: class TestPriorityQ {

8: public static void main(String[] args) {

9: //create 10 items priority queue

10: PriorityQ<Integer> q = new PriorityQ<Integer>(10);

11: int data;

12:

13: //populate queue with 10 random Integers

14: for(int i = 0; i < 10; i++) {

15: data = (int)(Math.random() * 100) + 1;

16: q.insert(data);

17: }

18: out.println("Queue after inserted 10 items");

19: out.println(q); //display contents of queue

20:

21: //remove 5 items from queue

22: for(int i = 0; i < 5; i++) {

23: data = q.remove();

24: out.println("Removed: " + data);

25: }

26: out.println("Queue after removed 5 items");

27: out.println(q); //display contents of queue

28:

29: //insert 2 more items

30: q.insert(99);

31: q.insert(37);

32: out.println("Queue after inserted 2 more items");

33: out.println(q); //display contents of queue

34: }

35: }

ผลลพธทไดคอ Queue after inserted 10 items

rear->(97, 86, 81, 80, 71, 71, 60, 42, 34, 23)<-front

Removed: 23

Removed: 34

Removed: 42

Removed: 60

Removed: 71

Queue after removed 5 items

rear->(97, 86, 81, 80, 71)<-front

Queue after inserted 2 more items

rear->(99, 97, 86, 81, 80, 71, 37)<-front

ผอานควรทบทวนถง code ของ PriorityQ โดยเฉพาะการน าขอมลเขา สวนการดงขอมลออกนนแทบจะไมมอะไรเลย เพราะเราดงขอมลออกทางทายสด ดงทไดกลาวไวแลวกอนหนาน ถาจะพดถงประสทธภาพของการท างานของ Priority queue สงทเรานาจะกงวลมากทสดคอ การน าขอมลเขา เนองจากวาเราตองคนหาต าแหนงทเหมาะสมของขอมล ดงนนเวลาของการท างานสวนใหญจงใชไปกบการน าขอมลเขา แตถาวเคราะหตามหลกการของ Big O แลวประสทธภาพการท างานของของ Priority queue นนเปนเพยงแค O(n) เพราะวาข นอยกบจ านวนของขอมลทมอยใน queue เทานน (ม loop เพยงหนง loop)

Page 23: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

91

3.3 กำรใช class ArrayList สรำง Stack และ Queue ArrayList เปนโครงสรางท Java มใหส าหรบการท างานกบขอมลทถกเกบในลกษณะของ list หรอ array (ดบททหนง) เราจะใช method ตาง ๆ จาก ArrayList มาชวยในการจดการกบขอมลของ Stack และ Queue โดยกอนอนเราจะมาดกนถงการสราง Stack จาก ArrayList ทวา

1: /**

2: Stack using ArrayList to manipulate data

3: */

4:

5: import java.util.ArrayList;

6:

7: public class ArrayListStack<T> {

8: private ArrayList<T> list;

9: private int top;

10:

11: //default constructor

12: public ArrayListStack() {

13: list = new ArrayList<T>();

14: top = -1;

15: }

16:

17: //insert item onto stack

18: public void push(T item) {

19: list.add(++top, item);

20: }

21:

22: //remove item from stack

23: public T pop() {

24: return list.remove(top--);

25: }

26:

27: //display content of stack

28: public String toString() {

29: StringBuffer buf = new StringBuffer();

30: buf.append("(" + list.get(0));

31: for(int i = 1; i < list.size(); i++)

32: buf.append(", " + list.get(i));

33: return new String(buf + ")<-top");

34: }

35:

36: //testing module

37: public static void main(String[] args) {

38: //create new stack

39: ArrayListStack<String> stk = new ArrayListStack<String>();

40:

41: //insert 4 items and display content

42: stk.push("Java");

43: stk.push("C++");

44: stk.push("Visual Basic");

45: stk.push("C#");

46: System.out.println(stk);

47:

48: //remove an item and display content afterward

49: System.out.println("Pop " + stk.pop());

50: System.out.println(stk);

51: }

52: }

เราใช method add() ส าหรบการ push ใช method remove() ส าหรบการ pop สวนการ

แสดงผลเราใช get() เปนตวดงขอมลออกจาก ArrayList ตาม index ทก าหนดให ผลลพธทเราไดจากการ run คอ (Java, C++, Visual Basic, C#)<-top

Pop C#

(Java, C++, Visual Basic)<-top

ตอไปเราจะมาดกนถงการน าเอา ArrayList มาเปนโครงสรางของ Queue

1: /**

Page 24: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

92

2: Queue using ArrayList to manipulate data

3: */

4:

5: import java.util.ArrayList;

6:

7: public class ArrayListQueue<T> {

8: private ArrayList<T> list;

9: private int front, rear;

10:

11: //default constructor

12: public ArrayListQueue() {

13: list = new ArrayList<T>();

14: front = rear = 0;

15: }

16:

17: //empty queue

18: public boolean empty() {

19: if(list.isEmpty())

20: return true;

21: return false;

22: }

23:

24: //insert item into queue

25: public void put(T item) {

26: list.add(rear++, item);

27: }

28:

29: //remove item from queue

30: public T get() {

31: if(list.isEmpty()) {

32: System.out.println("ERROR -Queue is empty!");

33: System.exit(1);

34: }

35: return list.remove(front);

36: }

37:

38: //display content of queue

39: public String toString() {

40: if(list.isEmpty())

41: return new String("Queue is empty.");

42:

43: StringBuffer buf = new StringBuffer();

44: buf.append("(" + list.get(0));

45: for(int i = 1; i < list.size(); i++)

46: buf.append(", " + list.get(i));

47: return new String(buf + ")<-rear");

48: }

49:

50: public static void main(String[] args) {

51: //create new queue

52: ArrayListQueue<String> que = new ArrayListQueue<String>();

53: //insert 4 items and display content

54: que.put("Java");

55: que.put("C++");

56: que.put("Visual Basic");

57: que.put("C#");

58: System.out.println(que);

59: //remove item and display content afterward

60: System.out.println("Get " + que.get());

61: System.out.println(que);

62: System.out.println("Get " + que.get());

63: System.out.println(que);

64: System.out.println("Get " + que.get());

65: System.out.println(que);

66: System.out.println("Get " + que.get());

67: System.out.println(que);

68: }

69: }

เรายงคงใช method add() ส าหรบการน าขอมลเขา และ method remove() ส าหรบการน าขอมลออก แตเราใชตวแปร front และ rear เปนตวก าหนดการน าขอมล เขา/ออก ผลลพธทเรา

ไดจากการ run คอ

Page 25: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

93

(Java, C++, Visual Basic, C#)<-rear

Get Java

(C++, Visual Basic, C#)<-rear

Get C++

(Visual Basic, C#)<-rear

Get Visual Basic

(C#)<-rear

Get C#

Queue is empty.

ผอานควรพจารณาถงขอด (หรอขอเสย) ของการน าส งทมอยแลวมาประยกตใชใหม ส าหรบงานตาง ๆ บางครงการออกแบบโครงสรางใหมจากศนยอาจเสยเวลาโดยใชเหต หากมส งทสามารถน ามาใชได หลาย ๆ ครงการน าเอาโครงสรางทมอยแลวมาปรบปรงเพมเตม เพอรองรบงานใหม ๆ ท าใหการออกแบบใชเวลานอยลง 3.4 กำรใช class Stack ของ java Java ม class Stack ทเราสามารถเรยกใชไดเหมอนกบ class ตวอน ๆ โปรแกรมตวอยางตอไปนเปนการแสดงการใช class Stack พรอมกบการใช for/in loop ทมอยใน Java 1.5

1: /**

2: Stack from Java (1.5)

3: */

4:

5: import java.util.Stack;

6:

7: class JavaStack {

8: public static void main(String[] args) {

9: Stack<String> stk = new Stack<String>();

10:

11: //push items onto stack

12: stk.push("Chiang Mai");

13: stk.push("Chiang Rai");

14: stk.push("Chiang Kong");

15:

16: printStack(stk);

17:

18: //pop items from stack

19: System.out.println("Pop: " + stk.pop());

20: printStack(stk);

21: }

22:

23: //iterate over stack's content

24: public static void printStack(Stack<String> stack) {

25: System.out.println("Content:");

26: for(String s : stack) {

27: System.out.println(s);

28: }

29: }

30: }

วธการเรยกใช Stack กเหมอนกบการเรยกใช class อน ๆ ในโปรแกรมของเรา เราไดประกาศตวแปร stk ใหเปน stack ทม String เปนขอมลดวยค าสง Stack<String> stk = new Stack<String>();

คาทอยในเครองหมาย <> จะเปนตวบอกชนดของขอมลทเราตองการเกบใน stack ซงถาเรา

ตองการเกบ Integer เรากเพยงแคประกาศ Stack<Integer> s = new Stack<Integer>

การน าขอมลเขากเชนเดยวกนกบทเราเคยท าคอ เรยกใช method push() ไดทนท เชน stk.push("Chiang Mai");

Page 26: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

94

ส าหรบการแสดงขอมลทงหมดทมอยใน stack เราเรยกใช for/in loop ซงเปน for-loop ตวใหมท Java 1.5 มให วธการเขาหาขอมลทเราใชกคอ บอกชนดของขอมลทเราเกบไวใน stack ใหกบ for/in loop ดวยการประกาศตวแปร s ใหเปน String พรอมกบบอกทอยท string เหลานถกเกบไว ซงกคอ stk (หรอตวแปรทช อยท เดยวกน เชน stack) for(String s : stack) {

System.out.println(s);

}

เมอเรา run โปรแกรม JavaStack.java ผลลพธทเราไดคอ Content:

Chiang Mai

Chiang Rai

Chiang Kong

Pop: Chiang Kong

Content:

Chiang Mai

Chiang Rai

ผอานควรใชเวลาสกเลกนอยในการศกษาถงการใช Stack (หรอแมแต Queue) ท Java มให จากคมอทมใหจาก sun เพอใหเกดความเขาใจมากยงข น ตวอยางตอไปจะเปนตวอยางสดทายในบทนทเรยกใช class PriorityQueue ของ Java 3.5 กำรใช class PriorityQueue การเรยกใช class PriorityQueue กเหมอนกบการเรยกใช class ArrayList ทเราไดแสดงให ดกอนหนาน ตวอยางของเราจะเปนตวอยางแบบงาย ๆ ทแสดงใหเหนการน าขอมลเขา และการดงขอมลออกดวยการใช method offer() และ method poll()

1: /**

2: Java's PrioirtyQueue

3: */

4:

5: import java.util.PriorityQueue;

6:

7: class JavaPriorityQueue {

8: public static void main(String[] args) {

9: PriorityQueue<String> q = new PriorityQueue<String>();

10:

11: //insert 4 items

12: q.offer("Chiang Mai");

13: q.offer("Bangkok");

14: q.offer("Ayudhaya");

15: q.offer("Nakhon Nayok");

16:

17: //display items in queue

18: for(String s : q)

19: System.out.println(s);

20:

21: //remove 1 item

22: System.out.println("Item removed: " + q.poll());

23: }

24: }

เราน าขอมลชนด String เขาส queue ดวยการเรยกใช method offer() และดงขอมลออกดวยการเรยกใช poll() ทงนผอานสามารถเรยกใช method add() และ method remove() ทมใหกได การจดวางขอมลใน priority queue ของ Java นนจดวางตาม natural order ของขอมลทน าเขา ดวยการใช comparable interface เปนตวก าหนด ผลลพธทเราไดจากการ run โปรแกรม JavaPriorityQueue.java คอ Ayudhaya

Chiang Mai

Bangkok

Nakhon Nayok

Page 27: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

95

Item removed: Ayudhaya

ผอานอาจสงสยวาท าไมผลลพธทไดจงไมจดเรยงตามล าดบกอนหลงของตวอกษรทอยใน string ค าตอบกคอ การแสดงผลดวย iterator ใน for/loop นน ไมการนตการจดเรยงของขอมลเมอสงออกมา แตจรง ๆ แลวขอมลมการจดเรยงซงสามารถตรวจสอบไดดวยการ poll ขอมลใน queue ออกใหหมด 3.6 กำรใช Linked-List ส ำหรบกำรสรำง Stack และ Queue เราไดออกแบบ Stack ทใช array เปนตวจดเกบขอมลมากอนหนาน ณ เวลานเราจะทดลองใช Linked-List เปนตวเกบขอมลของ Stack ซงเปนส งทท าไดไมยากดงทจะแสดงใหเหนดวย code ขางลางน (ด class MyLinkedList ในบทท 2)

1: /**

2: Stack using Linked-List as storage

3: */

4:

5: public class LinkedStack<T extends Comparable<? super T>> {

6: protected MyLinkedList<T> list;

7:

8: //default constructor

9: //calling LinkedList's constructor

10: public LinkedStack() {

11: list = new MyLinkedList<T>();

12: }

13:

14: //insert item onto Stack using LinkedList's insert()

15: public void push(T item) {

16: list.insert(item);

17: }

18:

19: //remove item from Stack using LinkedList's remove()

20: public T pop() {

21: //cannot remove if empty

22: if(empty())

23: return null;

24: //return item removed from list

25: return list.remove();

26: }

27:

28: //calling LinkedList's empty()

29: public boolean empty() {

30: return list.size() == 0;

31: }

32:

33: //display contents of list via System.out.println()

34: public String toString() {

35: //if empty, display top->()

36: //otherwise return new String to avoid null

37: //pointer exception in System.out.println()

38: if(empty()) {

39: System.out.println("top->()");

40: return new String();

41: }

42: //items are in list - display them

43: else {

44: StringBuffer buf = new StringBuffer();

45: buf.append("top->(" + list.peek(0));

46: for(int i = 1; i < list.size(); i++)

47: buf.append(", " + list.peek(i));

48: buf.append(")");

49: return new String(buf);

50: }

51: }

52: }

จาก code ทใหจะเหนวาเราแทบไมตองท าอะไรเลย นอกจากเรยกใช method ของ class MyLinkedList ท าหนาทใหเรา ตงแตการสราง Stack การน าขอมลเขา และการแสดงผลขอมล สวนทเราไดปรบปรงกคอ การสราง method toString() ใหรองรบ null pointer ทเกดข นจาก

Page 28: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

96

การท list ไมมขอมลอย (toString() ทเราเขยนขนกอนหนานไมรองรบขอมลทเปน null ดงนนผอานควรเปลยนใหเปนแบบเดยวกนกบ toString() ทเราเขยนขนใหมน) หลงจากททดสอบดวยโปรแกรมทเหนน

1: /**

2: Testing stack that uses LinkedList stores data

3: */

4:

5: class LinkedStackTest {

6: public static void main(String []args) {

7: LinkedStack<Character> stack = new LinkedStack<Character>();

8:

9: //populate stack with chars

10: for(char i = 'A'; i <= 'K'; i++) {

11: stack.push(i);

12: System.out.println(stack);

13: }

14:

15: //remove 5 items form Stack

16: for(int i = 0; i < 5; i++) {

17: stack.pop();

18: System.out.println(stack);

19: }

20:

21: //insert 2 more chars

22: stack.push('Z');

23: stack.push('Q');

24: System.out.println(stack);

25: }

26: }

ผลลพธทไดคอ top->(A)

top->(B, A)

top->(C, B, A)

top->(D, C, B, A)

top->(E, D, C, B, A)

top->(F, E, D, C, B, A)

top->(G, F, E, D, C, B, A)

top->(H, G, F, E, D, C, B, A)

top->(I, H, G, F, E, D, C, B, A)

top->(J, I, H, G, F, E, D, C, B, A)

top->(K, J, I, H, G, F, E, D, C, B, A)

top->(J, I, H, G, F, E, D, C, B, A)

top->(I, H, G, F, E, D, C, B, A)

top->(H, G, F, E, D, C, B, A)

top->(G, F, E, D, C, B, A)

top->(F, E, D, C, B, A)

top->(Q, Z, F, E, D, C, B, A)

จะเหนไดวาการน าเอา code กลบมาใชใหมลดเวลาในการออกแบบและเขยน code ไดดพอสมควร ส งทจะตองค านงถงกคอ กระบวนการตาง ๆ ทอาจตองเพมใหกบ code เพอใหการท างานมประสทธภาพมากขน เชนเดยวกนกบ Stack เราสามารถทจะเขยน code รองรบการท างานในรปแบบของ Queue โดยใช Linked-List เปนตวจดการกบขอมลให เราสามารถทจะใช Linked-List แบบใดกไดทได กลาวไวแลวเปนตวจดการกบขอมลใหกบ Queue ไมวาจะเปน Linked-List ทเขาและออกทางดานหนา หรอวา Linked-List ทสามารถทจะน าขอมลเขาไดทงทางดานหนาและดานหลง ทงนกตองข นอยกบผอานวาตองการใชตวไหน ตวอยางทจะใหตอไปเปนการน าเอา Linked-List ทใช

การใสขอมลทางดานหลง และดงขอมลออกทางดานหนาเปนหลก เพอใหเหมาะสมกบลกษณะเฉพาะของ Queue (FIFO)

1: /**

2: Queue using LinkedList as storage

3: */

4:

Page 29: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

97

5: public class LinkedQueue<T extends Comparable<? super T>> {

6: //create list to hold data

7: protected MyLinkedList<T> list;

8:

9: //default constructor

10: //calling LinkedList's constructor

11: public LinkedQueue() {

12: list = new MyLinkedList<T>();

13: }

14:

15: //insert item via LinkeList's insertEnd()

16: public void insert(T item) {

17: list.insertEnd(item);

18: }

19:

20: //remove item via LinkedList's remove()

21: public T remove() {

22: //cannot remove if empty

23: if(empty())

24: return null;

25: //return item removed

26: return list.remove();

27: }

28:

29: //call LinkedList's empty()

30: public boolean empty() {

31: return list.empty();

32: }

33:

34: //display contents of list via System.out.println()

35: public String toString() {

36: //if empty, display front->()

37: //otherwise return new String to avoid null

38: //pointer exception in System.out.println()

39: if(empty()) {

40: System.out.println("front->()<-rear");

41: return new String();

42: }

43: //items are in list - display them

44: else {

45: StringBuffer buf = new StringBuffer();

46: buf.append("front->(" + list.peek(0));

47: for(int i = 1; i < list.size(); i++)

48: buf.append(", " + list.peek(i));

49: buf.append(")<-rear");

50: return new String(buf);

51: }

52: }

53: }

เชนเดยวกนกบการใช Linked-List ในการเกบขอมลให Stack การใช Linked-List ส าหรบการเกบขอมลกเชนเดยวกน เราเพยงแตเรยก method ทเกยวของของ Linked-List มาท างานใหเรา

โดยเราจะเนนการเรยกใช insertEnd() ส าหรบการน าขอมลเขา และ remove() ส าหรบการดงขอมลออก และเมอเราทดสอบดวยโปรแกรม LinkedQueueTest.java น

1: class LinkedQueueTest {

2: public static void main(String []args) {

3: LinkedQueue<Character> queue = new

LinkedQueue<Character>();

4:

5: //populate Stack with 10 random Integers

6: for(char c = 'Z'; c > 'K'; c--) {

7: queue.insert(c);

8: System.out.println(queue);

9: }

10:

11: //remove 5 items form queue

12: for(int i = 0; i < 5; i++) {

13: queue.remove();

14: System.out.println(queue);

15: }

16:

Page 30: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

98

17: //insert 2 more Integers

18: queue.insert('A');

19: queue.insert('B');

20: System.out.println(queue);

21: }

22: }

ผลลพธทไดคอ front->(Z)<-rear

front->(Z, Y)<-rear

front->(Z, Y, X)<-rear

front->(Z, Y, X, W)<-rear

front->(Z, Y, X, W, V)<-rear

front->(Z, Y, X, W, V, U)<-rear

front->(Z, Y, X, W, V, U, T)<-rear

front->(Z, Y, X, W, V, U, T, S)<-rear

front->(Z, Y, X, W, V, U, T, S, R)<-rear

front->(Z, Y, X, W, V, U, T, S, R, Q)<-rear

front->(Z, Y, X, W, V, U, T, S, R, Q, P)<-rear

front->(Z, Y, X, W, V, U, T, S, R, Q, P, O)<-rear

front->(Z, Y, X, W, V, U, T, S, R, Q, P, O, N)<-rear

front->(Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M)<-rear

front->(Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M, L)<-rear

front->(Y, X, W, V, U, T, S, R, Q, P, O, N, M, L)<-rear

front->(X, W, V, U, T, S, R, Q, P, O, N, M, L)<-rear

front->(W, V, U, T, S, R, Q, P, O, N, M, L)<-rear

front->(V, U, T, S, R, Q, P, O, N, M, L)<-rear

front->(U, T, S, R, Q, P, O, N, M, L)<-rear

front->(U, T, S, R, Q, P, O, N, M, L, A, B)<-rear

เชนเดยวกนกบ Stack ทใช Linked-List เปนตวจดเกบขอมล method อน ๆ ทจะท าใหงานตาง ๆ ดย งข นกตองมการออกแบบและน ามาใชกบ Queue ตอไป สรป ในบทนเราไดพดถงการออกแบบ Stack ทงทใช array ทมขอจ ากดในเรองของขนาด และ array ทมความสามารถทจะขยายขนาดเพอรองรบการน าขอมลเขา รวมไปถงการออกแบบและการใช Queue ทมการใชโครงสรางของ circular array เปนตวเกบขอมล การออกแบบและการใชงาน Priority queue โดยรวมแลวเราไดพดถง การใช array ทมขอจ ากดในเรองของขนาดเปนตวเกบขอมลของ Stack การใช Dynamic array ในการจดการกบขนาดของ Stack ตวอยางการใช Stack กบการ reverse String ตวอยางการใช Stack กบการเปลยนเลขฐานสบใหเปนเลขฐานสอง การใช circular array ในการเกบขอมลของ Queue การน าขอมลเขา และดงขอมลออกจาก Queue การท างานกบ Priority queue การออกแบบ Stack และ Queue ดวย ArrayList การใช class Stack และ PriorityQueue ของ Java การใช Linked-List ในการสราง Stack และ Queue แบบฝกหด 1. จงเขยน method ทสงคาของขอมลทอยดานลางสด (bottom) ของ stack ใหกบผเรยก ให

เขยนโปรแกรมทดสอบ method ทเขยนขน 2. จงเขยน method ทสงคาของขอมล ณ ต าแหนงทก าหนดให (nth element) ของ stack

(นบจากดานบน หรอ top) ใหกบผเรยก ใหเขยนโปรแกรมทดสอบ 3. จงเขยนโปรแกรมทท าหนาทสลบขอมลของ stack จากดานบนสดานลาง (top to bottom)

Page 31: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

บทท 3 Stack และ Queue

99

4. จงเขยนโปรแกรมทม menu ส าหรบการท างานตาง ๆ ทเกยวของกบ stack เชน push, pop, peek, จ านวนขอมลทมอยใน stack และ display ขอมลทมอยใน stack ทงหมด

5. จากขอมลในขอ 4 เปลยนการใช stack ใหเปนการใช queue 6. จงเขยนโปรแกรมทสลบต าแหนงขอมลใน queue (front to rear) 7. จากขอมลในขอ 2 ใหใช queue แทน stack 8. จงเขยน method ทท าหนาท insert ขอมลเขาส queue จากทางดานหนา ใหเขยน

โปรแกรมทดสอบ

9. จงเขยน method ทดงขอมลออกจากทางดานหลงของ queue ใหเขยนโปรแกรมทดสอบ 10. จงเขยนโปรแกรมทน าขอมลจาก stack เขาส queue โดยทขอมลทอยดานหนาสดของ

stack (top) กยงอยดานหนา ของ queue (front) 11. ก าหนดให queue เปน queue ทเกบขอมลชนด Integer จงเขยน method ท delete

ขอมลทเปน negative ทงหมดออกจาก queue โดยทขอมลทเหลออยใน queue ยงคงอย

ในต าแหนงทเรยงกนอยแบบเดม (same order) 12. จงเขยน method ทสงคา true ถา queue 2 ตวมขอมลเหมอนกน และสงคา false ถาม

ขอมลทแตกตางกน 13. จงเขยนโปรแกรมทน าเอา stack และ queue มาอยใน menu เดยวกน (ขอ 4 รวมกบขอ 5) 14. จงอธบายถงการท างานของ Priority queue ทใช array ในการจดเกบขอมลทมการ

เรยงล าดบ จาก นอยไปหามากวาจะมผลแตกตางจากการใช array ทเรยงจากมากไปหานอยอยางไร การดงขอมลออก และการน าขอมลเขาตองท าอยางไร ใหเขยนโปรแกรมทดสอบ

15. จงเขยนโปรแกรมทใช circular array ในการเกบขอมลของ Priority queue 16. จงเขยนโปรแกรมทใช class Vector เปนโครงสรางหลกในการเกบขอมลของ Queue และ

Stack ใหเขยนโปรแกรมทดสอบ method ตาง ๆ ทมอยใน Queue และ Stack ทสรางขน 17. จงสราง class Stack ทม method ทยอมใหผใชน าขอมลเขา หรอดงขอมลออก ณ

ต าแหนงทก าหนดให 18. เชนเดยวกบขอ 17 แตเปลยนเปน Queue แทน 19. Java 1.5 ม interface ชอ Queue ทเราสามารถเรยกใชในการท างานตาง ๆ ทเกยวของกบ

queue ได โดยทเราสามารถจะก าหนดใหโครงสรางของการเกบขอมลเปนอะไรกไดทไดมการ implement Queue interface เชน เราอาจประกาศโครงสราง queue ของเราเปน

Queue<String> myQueue = new LinkedList<String>(); จงเขยนโปรแกรมทแสดงการใชโครงสรางดงกลาว โดยมกระบวนการทเกยวของกบ queue ทงหมด เชน การน าขอมลเขา การดงขอมลออก เปนตน

20. จงสราง class PriorityQueue ทใช class ArrayList เปนโครงสรางหลกในการเกบขอมล

โดยมเงอนไขวา ขอมลทม priority สงสดจะตองอยดานหลงสดของ queue เทานน และให เขยนโปรแกรมทดสอบโครงสรางดงกลาว

Page 32: Stack Queue เป็นโครงสรา้งทใี่ชเ้ก็บขอ้มูลในอกีรูปแบบหนง ...sci.feu.ac.th/faa/dsa/bookPDFs/chap3-StackQueue.pdf ·

Stack และ Queue บทท 3

100

21. ก าหนดใหม queue อยสองตว โดยทตวแรกเปน queue ทมการจดเรยงขอมลจากนอยไปหามาก และตวทสองเปน queue ทมการจดเรยงจากมากไปหานอย จงเขยนโปรแกรมทท าการรวมเอาขอมลทงสองทอยใน queue เขาดวยกนโดยก าหนดให ขอมลหลงจากการรวมแลวใหอยในรปแบบของการจดเรยงจาก มากไปหานอย หรอนอยไปหามาก ทงนจะข นอยกบขอมลทอยดานหนาสดของ queue ทงสองตว ถาขอมลตวแรกสดของ queue ตวแรกนอยกวา ขอมลตวแรกสดของ queue ตวทสองใหจดเรยงจากมากไปหานอย ใหท าการตรงกนขามถาขอมลตวแรกไมเปนไปตามทกลาวไว

22. จงออกแบบ stack ทใช linked list เปนโครงสรางหลกในการจดการขอมล 23. จงออกแบบ queue ทใช linked list เปนโครงสรางหลกในการจดการขอมล

24. จากโจทยในขอ 22 ใหเปลยนมาใช circular linked list แทน 25. จากโจทยในขอ 23 ใหเปลยนมาใช circular linked list แทน