Page 1

!"

แผนการสอนประจําบทเรียน รายชือ่ อาจารยผจู ดั ทํา สุณี รักษาเกียรติศักดิ์ หัวขอของเนื้อหา ตอนที่ 5.1 ชนิดขอมูลแบบสแตก (2 คาบ) เรือ่ งที่ 5.1.1

การกําหนดคุณลักษณะเฉพาะของสแตก

เรือ่ งที่ 5.1.2

การสรางสแตกดวยอะเรย

เรือ่ งที่ 5.1.3

การสรางสแตกดวยลิงคลสิ ต

เรือ่ งที่ 5.1.4

การใชสแตก

เรือ่ งที่ 5.1.5

การเปรียบเทียบประสิทธิภาพของการสรางสแตกดวยอะเรยและลิงคลสิ ต

ตอนที่ 5.2 การประยุกตใชสแตก (1 คาบ) เรือ่ งที่ 5.2.1

การจัดการหนวยความจํา

เรือ่ งที่ 5.2.2

การใชสแตกในกระบวนการเรียกใชโพรซีเจอรหรือฟงชันก

เรือ่ งที่ 5.2.3

การตรวจสอบอักขระสมดุล

เรือ่ งที่ 5.2.4

การคํานวณคานิพจนเลขคณิต

แนวคิด 1. ชนิดขอมูลแบบสแตกมีการประยุกตใชมากในวิทยาการคอมพิวเตอร 2. ชนิดขอมูลแบบสแตกมีโครงสรางขอมูลแบบเชิงเสน (linear) 3. ชนิดขอมูลแบบสแตกมีคุณสมบัติเฉพาะคือ สมาชิกขอมูลที่เขาไปในสแตกทีหลังจะออกกอน (Last In First Out หรือ LIFO) 4. การดําเนินงานกับสแตกไดแก การสรางสแตก (create) การนําสมาชิกลงสแตก (push) การ นําสมาชิกออกจากสแตก (pop) การทดสอบวาสแตกวางหรือไม (empty) การทดสอบวาส แตกเต็มหรือไม (full) การทําใหสแตกเปนสแตกวาง (clear) 5. การที่จะใหผูใชเขาใจคุณสมบัติของสแตกที่ตรงกัน จะตองมีออกแบบคุณสมบัตขิ องสแตก โดยการเขียนคุณลักษณะเฉพาะ (specification) ของสแตกที่เราตองการอยางชัดเจน


#$ 6. เมือ่ มีการเขียนคุณลักษณะเฉพาะทีช่ ดั เจนแลว ผูส รางก็สามารถจะสรางสแตกตามทีอ่ อก แบบไวได โดยรายละเอียดของการสรางจะซอนจากผูใช 7. ในการสรางสแตกผูส รางตองดําเนินการสองสิง่ ใหญ ๆ คือ เลือกการแทนที่ขอมูลของสแตก และสรางการดําเนินงานโดยใชการแทนทีข่ อ มูลทีเ่ ลือกแลว 8. ในการสรางสแตกผูสรางสามารถที่จะเลือกใชการแทนที่ขอมูลของสแตกแบบอะเรยหรือลิงค ลิสตกไ็ ด 9. ในการใชชนิดขอมูลแบบสแตก ผูใชเพียงแตใชตามคุณลักษณะเฉพาะที่ออกแบบไวเทานั้น ไมตองสนใจวาผูสรางจะเลือกการแทนที่ขอมูลของสแตกอยางไร และสรางมาดวยวิธีการ อยางไร วัตถุประสงค หลังจากศึกษาบทเรียนที่ 5 แลว นักศึกษาสามารถ 1. บอกถึงคุณลักษณะเฉพาะของสแตกได วาสแตกมีสมาชิกเปนอยางไร มีโครงสรางขอมูล อยางไร และสามารถดําเนินงานอะไรกับสแตกไดบา ง 2. สรางสแตกโดยใชการแทนที่ขอมูลแบบอะเรยได 3. สรางสแตกโดยใชการแทนที่ขอมูลแบบลิงคลิสตได 4. ใชสแตกหรือทดสอบการใชงานของสแตกได 5. เปรียบเทียบประสิทธิภาพระหวางการสรางสแตกดวยอะเรยและลิงคลสิ ต ในรูปของฟงชันบิ๊ก โอ (function Oh) ได 6. บอกตัวอยางการประยุกตใชสแตกในสาขาวิชาวิทยาการคอมพิวเตอรได กิจกรรมการเรียนการสอน กิจกรรมทีน่ กั ศึกษาตองทําสําหรับการเรียนการสอน ไดแก 1. ศึกษาเอกสารชุดวิชา/โฮมเพจชุดวิชา ตอนที่ 5.1 และตอนที่ 5.2 2. ทํากิจกรรมของบทเรียนที่ 5 3. ทําแบบประเมินผลของบทเรียนที่ 5 เอกสารประกอบการสอน 1. เอกสารชุดวิชา สื่อการสอน 1. โฮมเพจชุดวิชา 2. สไลดประกอบการบรรยาย (Powerpoint) 3. โปรแกรมคอมพิวเตอร


#% ประเมินผล 1. ประเมินผลจากกิจกรรมที่ทํา 2. ประเมินผลจากคําถามทายบทเรียน


#& ตอนที่ 5.1 สแตก หัวเรื่อง เรือ่ งที่ 5.1.1

การกําหนดคุณลักษณะเฉพาะของสแตก

เรือ่ งที่ 5.1.2

การสรางสแตกดวยอะเรย

เรือ่ งที่ 5.1.3

การสรางสแตกดวยลิงคลสิ ต

เรือ่ งที่ 5.1.4

การทดสอบการใชสแตก

เรือ่ งที่ 5.1.5

การเปรียบเทียบประสิทธิภาพของการสรางสแตกดวยอะเรยและลิงคลสิ ต

แนวคิด 1. การกําหนดคุณลักษณะเฉพาะของสแตกมีความสําคัญมากในการสือ่ สารระหวางผูส รางสแตก และผูใชสแตก โดยที่ผูใช ใชโดยทราบขอกําหนดจากคุณลักษณะเฉพาะที่กําหนด และผูส ราง ก็สรางตามคุณลักษณะเฉพาะทีก่ าํ หนด 2. ผูใชไมตองสนใจในรายละเอียดของการสราง ผูใชเพียงแตทราบวาสแตกมีคุณสมบัติอยางไร และสามารถดําเนินงานอะไรกับสแตกไดบา ง ในการดําเนินงานแตละอยางผูใชตองใหขอมูล เขาอยางไร และผูใชจะไดผลลัพธอะไรหลังจากใชการดําเนินงานนั้น ๆ 3. ผูสรางสามารถที่จะสรางสแตกโดยใชการแทนที่ขอมูลแบบอะเรยหรือลิงคลิสตก็ได โดยไมมี ผลตอการเรียกใชของผูใช วัตถุประสงค หลังจากที่ศึกษาตอนที่ 5.1 แลว นักศึกษาสามารถ 1. 2. 3. 4. 5. เรื่องที่ 5.1.1

เขียนคุณลักษณะเฉพาะของชนิดขอมูลแบบสแตก และบอกการดําเนินงานทีส่ าํ คัญของสแตก สรางสแตกดวยอะเรยได สรางสแตกดวยลิงคลสิ ตได ทดสอบการใชสแตกเพือ่ ตรวจสอบวาสแตกทีผ่ สู ราง สรางมา สรางไดถกู ตอง เปรียบเทียบประสิทธิภาพของการสรางสแตกดวยอะเรยและลิงคลสิ ตได การกําหนดคุณลักษณะเฉพาะของสแตก

ในการกําหนดคุณลักษณะเฉพาะของสแตก จะประกอบดวย 3 สวน ใหญ ๆ คือ • การกําหนดวาสมาชิกของสแตกที่ใชมีชนิดขอมูลเปนอะไร • การกําหนดวาสมาชิกของสแตกมีโครงสราง หรือความสัมพันธกันอยางไร • การกําหนดวาเราสามารถดําเนินงานอะไรกับสแตกไดบา ง


#' โดยรายละเอียดของคุณลักษณะเฉพาะของสแตกจะเปนดังนี้ คุณลักษณะเฉพาะ 5.1 คุณลักษณะเฉพาะของสแตก สมาชิก:

สมาชิกของสแตกจะมีชนิดเปนอยางไรก็ได แตในที่นี้สมมติใหมีชนิดเปน StdElement

โครงสราง:

สแตกจะมีโครงสรางแบบเชิงเสน และอันดับของการนําสมาชิกเขาและออกจากสแตกมี ความสําคัญ คือ สมาชิกที่เขาไปอยูในสแตกกอนจะออกจากสแตกหลังสมาชิกที่เขาไปใน สแตกทีหลัง นัน่ คือ การเขาทีหลังออกกอน (Last ln First Out หรือ LIFO)

การดําเนินงาน: มีการดําเนินงานทั้งหมด 6 การดําเนินงาน สัญลักษณ : ให S – pre

เปน สถานะของสแตกกอนการดําเนินงาน

S – post

เปน สถานะของสแตกหลังการดําเนินงาน

Pre

เปนเงือ่ นไขเริม่ ตนทีต่ อ งเปนจริงกอนการดําเนินงาน

Post

เปนผลลัพธจากการดําเนินงาน

Create Pre:

ไมมี

Post:

มีสแตกวางเกิดขึ้น

Push ( E : StdElement ) Pre:

สแตกยังไมเต็ม (ยังมีที่วาง)

Post:

สแตกจะมี E เปนสมาชิกลาสุดของสแตก หรือสมาชิกบนสุดของสแตก

Pop ( VAR E : StdElement ) Pre:

สแตกตองไมวาง

Post:

E เปนสมาชิกลาสุดของ S – pre และ S – post จะไมมี E เปนสมาชิกอีกตอไป

Empty : boolean Pre:

ไมมี

Post:

ถา สแตกไมมีสมาชิกอยูเลย แลว Empty จะเปนจริง ไมเชนนั้น Empty จะเปนเท็จ

Full : boolean Pre:

ไมมี

Post:

ถา สแตกมีสมาชิกเต็ม แลว Full จะเปนจริง ไมเชนนั้น Full จะเปนเท็จ

Pre:

ไมมี

Post:

สแตกจะเปนสแตกวาง

Clear


#( หมายเหตุ ในบทเรียนที่ 3 เราไดกลาวถึงชนิดขอมูล StdElement เปนดังนี้ TYPE

StdElement = RECORD Key : Keytype; Data : Datatype END;

ตัวอยาง 5.1 ตัวอยางสมาชิกขอมูลชนิดตาง ๆ ตัวอยางของชนิดขอมูล StdElement เชน Student หรือ Book ซึง่ มีชนิดเปนดังนี้ TYPE Student = RECORD Id : integer; {Key part} Name : string[20]; {Data part: Name,Math,Stat,Comp} Math, Stat, Comp : integer END;

TYPE Book = RECORD Call_no Author

: integer; {Key part} : string[15]; {Data part: Author, Title, Publisher, Status} Title : string[20]; Publisher : string[15]; Status : char; {I = Checked In, O = Checked Out}; END;

กิจกรรม 5.1 ฝกการเขียนคุณลักษณะเฉพาะของการดําเนินงาน ในคุณลักษณะเฉพาะขางตนของการดําเนินงาน Pop มีเงื่อนไขเริ่มตน (pre) วา สแตกตองไมเปน สแตกวาง หากเราเอาเงือ่ นไขเริม่ ตนนีอ้ อกไป นัน้ คือสแตกจะเปนสแตกวางก็ได ถาสแตกเปนสแตกวาง การ ดําเนินงานของ Pop ก็ไมสาํ เร็จ ซึง่ จะสงผลลัพธออกมาทางพารามิเตอร Fail จงเขียนคุณลักษณะเฉพาะของการดําเนินงาน Pop ใหมตามขอกําหนดที่กลาวขางตน เรื่องที่ 5.1.2 การสรางสแตกดวยอะเรย ในการสรางสแตกดวยอะเรย หมายถึงเราเลือกการแทนที่ขอมูลของสแตกดวยอะเรยซึ่งเปนการจัด สรรเนื้อที่หนวยความจําแบบสแตติก นัน้ คือ จะมีการกําหนดขนาดของสแตกลวงหนาวาจะมีขนาดเทาใดและ จะมีการจัดสรรเนื้อที่หนวยความจําใหเลย การสรางสแตกนีจ้ ะสรางในยูนติ ชือ่ StackUA ดังนี้ UNIT StackUA; INTERFACE CONST Maxsize = 100 {User supplied}; TYPE

KeyType = 1..100 {ID}; DataType = RECORD Name : string[20]; Math, Stat, Comp : integer; END; StdElement = RECORD

1 2 3 4 5 6 7 8 9 10 11


#) VAR

Key : KeyType; {User supplied} Data : DataType; {User supplied} END; S : ARRAY[1..Maxsize] OF StdElement; Top : 0..Maxsize;

PROCEDURE PROCEDURE PROCEDURE FUNCTION FUNCTION PROCEDURE

Create; Push(E : StdElement); Pop(VAR E : StdElement); Empty : boolean; Full : boolean; Clear;

IMPLEMENTATION PROCEDURE Create; BEGIN Top := 0 END; PROCEDURE Push(E : StdElement); BEGIN Top := Top + 1; S[Top] := E; END; PROCEDURE Pop(VAR E : StdElement); BEGIN

END; FUNCTION Empty : boolean; BEGIN IF Top = 0 THEN Empty := true ELSE Empty := false; END; FUNCTION Full : boolean; BEGIN IF Top = Maxsize THEN Full := true ELSE Full := false END; PROCEDURE Clear; BEGIN Top := 0 END; END.

โปรแกรม 5.1 การสรางสแตกดวยอะเรย ขอสังเกต ในการนิยาม VAR ขางตน ตัวแปร S และ Top จะเปนตัวแปรที่บงถึงสแตก

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61


#* กิจกรรม 5.2 ทดสอบการสรางชนิดขอมูลสแตกดวยอะเรย จงเขียนโคดของการดําเนินงาน Push ใหสมบูรณ พรอมทดสอบ UNIT StackUA ของโปรแกรม 5.1 โดยใหสมาชิกของสแตกมีชนิดเปน Student และใหชื่อไฟล source code เปน StackUA.pas และจง สังเกตวาเมือ่ คอมไพลผา นแลวจะเกิด object code ชื่อ StackUA.TPU


#! เรื่องที่ 5.1.3 การสรางสแตกดวยลิงคลิสต ในการสรางสแตกดวยลิงคลสิ ต หมายถึงเราเลือกการแทนทีข่ อ มูลของสแตกดวยลิงคลสิ ตซง่ึ เปนการ จัดสรรเนื้อที่หนวยความจําแบบไดนามิก นัน้ คือ หนวยความจําจะถูกจัดสรรเมื่อมีการขอใชจริง ๆ ระหวางการ ประมวลผลโปรแกรมผานตัวแปรชนิด pointer การสรางสแตกนีจ้ ะสรางในยูนติ ชือ่ StackUL ดังแสดงใน โปรแกรม 5.2


## UNIT StackUL; INTERFACE CONST Maxsize TYPE

= 100 { User supplied };

KeyType DataType

= 1..100 {ID}; = RECORD Name : string[20]; Math, Stat, Comp : integer; END; StdElement = RECORD Key : Keytype ; Data : Datatype ; END; pointer = ^Node; Node = RECORD El : StdElement; Next : pointer; END; VAR Top : pointer; {Top is stack} PROCEDURE Create; PROCEDURE Push (E : StdElement); PROCEDURE Pop (VAR E : StdElement); FUNCTION Empty : boolean; FUNCTION Full : boolean; PROCEDURE Clear; IMPLEMENTATION PROCEDURE Create; BEGIN Top := nil; END; PROCEDURE Push(E : StdElement); VAR P : pointer ; BEGIN new(P); P^.El := E; P^.Next := Top; Top := P; END; PROCEDURE Pop(VAR E : StdElement); VAR P : pointer; BEGIN P := Top; E := P^.EL; Top := Top^.Next; dispose(P); END; FUNCTION Empty : boolean ; BEGIN IF Top = NIL THEN Empty := true ELSE Empty := false; END; FUNCTION Full : boolean ; BEGIN Full := false END; PROCEDURE Clear; VAR P : pointer; BEGIN WHILE Top <> NIL DO BEGIN P := Top; Top := Top^.Next; dispose(P); END; END; END.

โปรแกรม 5.2 การสรางสแตกดวยลิงคลิสต

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68


#" หมายเหตุ 1. ถาเลือกใชการสรางสแตกดวยลิงคลสิ ต สแตกจะไมมีวันเต็มคราบใดที่ยังมีเนื้อที่ในหนวยความ จํา (ในฮีป) 2. เราสามารถจะใชการดําเนินงานทีม่ อี ยูแ ลว เชน Empty และ Pop ใน Clear ได ดังนี้ PROCEDURE Clear; VAR E : StdElement ; BEGIN WHILE NOT Empty DO Pop(E); END;

กิจกรรม 5.3 ทดสอบการสรางชนิดขอมูลสแตกดวยอะเรย จงทดสอบ UNIT StackUL ตามตัวอยางที่กลาวขางตน โดยใหสมาชิกของสแตกมีชนิดเปน Student และใหชื่อไฟล source code เปน StackUL.pas และจงสังเกตวาเมื่อคอมไพลผานแลวจะเกิด object code ชื่อ StackUL.TPU เรื่องที่ 5.1.4 การใชและการทดสอบสแตก เมือ่ เราสรางสแตกขึน้ มาแลว ไมวาจะเปนการแทนที่ขอมูลสแตกดวยอะเรย (StackUA.TPU) หรือ การแทนทีข่ อ มูลสแตกดวยลิงคลสิ ต (StackUL.TPU) ผูใชสามารถจะเรียกใชการดําเนินงานของสแตกไดใน รูปแบบเดียวกัน ไมขึ้นกับการแทนที่ขอมูลที่ใช ตัวอยางการทดสอบการใชงานของสแตกที่มีชนิดขอมูลสมาชิกเปน Book เปนดังนี้ PROGRAM StackT; USES wincrt, StackUA; VAR Choice : char; Data : Book; PROCEDURE MainMenu; BEGIN writeln(' ----------------------------------------'); writeln(' | MAIN MENU |'); writeln(' ----------------------------------------'); writeln(' | 1. Push data into Stack |'); writeln(' | 2. Pop data out of Stack |'); writeln(' | 3. Test whether Stack is empty |'); writeln(' | 4. Clear Stack |'); writeln(' | 9. Exit |'); writeln(' ----------------------------------------'); END; PROCEDURE GetElement (VAR E : Book); BEGIN

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18


"$ writeln('Please input data '); write('Call_no : '); readln(E.Call_no); write('Author : '); readln(E.Author); write('Title : '); readln(E.Title); write('Publisher : '); readln(E.Publisher); write('Status : '); readln(E.Status); write('Price : '); readln(E.Price); END; PROCEDURE PrintElement (E : Book); BEGIN WITH E DO writeln (Call_no:7, Author:15, Title:20, Publisher:15, Status:9, Price:6); END; BEGIN { Main } clrscr; create; MainMenu; writeln; write('Please enter your selection : '); readln(Choice); WHILE Choice <> '9' DO BEGIN CASE Choice OF '1' : BEGIN GetElement(Data); Push(Data); writeln ('One element is pushed on top of Stack'); END; '2' : BEGIN Pop(Data, Fail); IF Fail THEN writeln('Stack is empty, cannot pop') ELSE BEGIN writeln ('The top element of the stack before popping is:'); writeln ('Call_no':7, 'Author':15, 'Title':20, 'Publisher':15, 'Status':9, 'Price':6); PrintElement(Data); END; END; '3' : BEGIN IF Empty THEN writeln('Stack is empty') ELSE writeln('Stack is not empty'); END; '4' : BEGIN Clear; writeln ('Stack is clear'); END;

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68


"% ELSE

MainMenu;

END {CASE}; writeln; write('Please enter your selection : '); readln(Choice); END {WHILE}; writeln ('$$$ END TESTING GOOD BYE $$$'); readln; END.

69 70 71 72 73 74 75 76 77

โปรแกรม 5.3 การทดสอบการใชงานสแตก กิจกรรม 5.4 ทดสอบการใชงานสแตก จงทดสอบการใชงานสแตกโดยคอมไพลและรันโปรแกรมขางตน โดยใหชื่อเปน StackT.pas โดยทํา 2 ครัง้ ครั้งแรกเรียกใช USES StackUA และครั้งที่ 2 เรียกใช USES StackUL ซึ่งจะเห็นไดวาผูใชไมตอง เปลีย่ นแปลงโปรแกรมการเรียกใชเลย ไมวา ผูส รางจะสรางสแตกดวยอะเรยหรือลิงคลสิ ตกต็ าม เรื่องที่ 5.1.5 เปรียบเทียบประสิทธิภาพของการสรางสแตกดวยอะเรยและลิงคลิสต ในการเปรียบเทียบประสิทธิภาพของการสรางสแตกดวยอะเรยและลิงคลสิ ตนน้ั เราจะเปรียบเทียบ ใน 2 ดาน คือ 1. การเลือกการแทนทีข่ อ มูล 2. การสรางการดําเนินงาน ขอเปรียบเทียบของการเลือกการแทนที่ขอมูลของสแตก การเลือกการแทนทีข่ อ มูลสแตกดวยอะเรย มีขอจํากัดสําหรับขนาดของสแตกและจะตองจองเนื้อที่ เทากับขนาดที่ใหญที่สุดของสแตกไวเลย เพราะเปนการจัดสรรเนือ้ ทีใ่ นหนวยความจําแบบสแตติก สวนการ เลือกการแทนทีข่ อ มูลสแตกดวยลิงคลสิ ต ไมมีขอจํากัดของขนาดของสแตกและหนวยความจําจะถูกใชก็ตอ เมื่อมีขอมูลจริงๆ แลวเทานัน้ เพราะเปนการจัดสรรเนื้อที่หนวยความจําแบบไดนามิก ซึ่งทําใหประหยัดเนื้อ ที่ในหนวยความจํามากกวา แตการเขียนโคตสําหรับการแทนที่ขอมูลสแตกดวยอะเรยงายกวาการแทนที่ขอ มูลดวยลิงคลสิ ต ขอเปรียบเทียบของประสิทธิภาพของการดําเนินงาน ขอเปรียบเทียบของการดําเนินงานทัง้ 6 การดําเนินงานของสแตกทีส่ รางดวยอะเรยและสแตกทีส่ ราง ดวยลิงคลิสตดังแสดงในตาราง 5.1


"& ตาราง 5.1 เปรียบเทียบประสิทธิภาพของการดําเนินงานของสแตกที่สรางดวยอะเรยและลิงคลิสต การดําเนินงาน

สรางดวยอะเรย

สรางดวยลิงคลสิ ต

Create

O(1)

O(1)

Push

O(1)

O(1)

Pop

O(1)

O(1)

Full

O(1)

-

Empty

O(1)

O(1)

Clear

O(1)

O(n)

จะเห็นไดวาทุกการดําเนินงานของสแตกไมวาจะใชอะเรยหรือลิงคลิสตจะใชเวลาคงที่คือ 0(1) ไม ขึน้ อยูก บั จํานวนของขอมูลในสแตกยกเวนการดําเนินงานของ Clear สําหรับสแตกทีส่ รางดวยลิงคลสิ ตซง่ึ เวลาที่ใช Clear สแตกขึ้นอยูกับจํานวนขอมูลที่อยูในสแตกคือ 0(n) เมื่อ n คือจํานวนขอมูลที่อยูในสแตก


"' ตอนที่ 5.2 การประยุกตใชสแตก หัวเรื่อง เรือ่ งที่ 5.2.1

การจัดการหนวยความจํา

เรือ่ งที่ 5.2.2

การสรางสแตกในกระบวนการเรียกใชโพรซีเจอรหรือฟงชันก

เรือ่ งที่ 5.2.3

การตรวจสอบอักขระสมดุล

เรือ่ งที่ 5.2.4

การคํานวณคานิพจนเลขคณิต

แนวคิด ชนิดขอมูลแบบสแตกมีการประยุกตใชมากในการเขียนโปรแกรมของสาขาวิชาทางวิทยาการ คอมพิวเตอร เชน การจัดสรรหนวยความจําในการประมวลผลโปรแกรม และการคํานวณคานิพจนเลขคณิต เปนตน วัตถุประสงค หลังจากที่ศึกษาตอนที่ 5.2 แลว นักศึกษาสามารถ 1. บอกถึงการประยุกตใชชนิดขอมูลแบบสแตกในการโปรแกรมของสาขาวิชาวิทยาการ คอมพิวเตอร เรื่องที่ 5.2.1 การจัดการหนวยความจํา ในการจัดการหนวยความจําของคอมพิวเตอร โครงสรางขอมูลแบบสแตกคู (double stack) ไดนาํ มาประยุกตใช หนวยความจําสามารถแทนดวยโครงสรางขอมูลแบบอะเรยดังนี้ CONST M : Number of memory bytes VAR Ram : ARRAY [0..M-1] OF byte;

โดยทั่วไปการจัดการหนวยความจําจะเปนดังนี้ Reserved By System Low Memory

Programs And procedures

Dynamic variable heap !

Local

Available space

Operating Variable system stack " High Memory

ลองมาดูตัวอยางของการจัดเก็บคาของตัวแปรในหนวยความจําในตัวอยางโปรแกรม 5.4


"(

2 3 6

3 4

5

1 2 7 8

PROGRAM MemAllocation; VAR P, Q, R : { User defined } ; PROCEDUDE A; VAR S : { User defined } ; BEGIN { A } ----> ----> B ; ----> END ; PROCEDURE B; TYPE pointer = ^Node; Node = RECORD El : StdElement ; Next : pointer ; END ; VAR D : pointer ; X, Y : {User defined}; BEGIN { B } ----> new(D); ----> new(D); new (D); ----> END; BEGIN {Main} ----> ----> A; ----> END. ---->

โปรแกรม 5.4 การประยุกตใชสแตกในการจัดการหนวยความจํา ภาพของคาของตัวแปรในหนวยความจําเมื่อกําลังประมวลผลโปรแกรม ณ จุดตาง ๆ เปน ดังนี้ คําสัง่ แรกของ BEGIN {Main} เนื้อที่หนวยความจําในสแตกจะถูกใชสําหรับตัวแปร P, Q, R Reserved By System

Programs And procedures

P Operating Q system R ↑ Top of heap

2. เมื่อเรียกใชโพรซีเจอร A ณ คําสัง่ แรกของ BEGIN {A}

↑ Top of stack


")

Reserved By System

Programs And procedures

S

↑ Top of heap

P Operating Q system R

↑ Top of stack

3. เมื่อเรียกใชโพรซีเจอร B ณ คําสัง่ แรกของ BEGIN {B} Reserved By System

Programs And procedures

X S Y

P Operating Q system R

↑ Top of heap

↑ Top of stack

D

X S Y

↑ Top of heap

↑ Top of stack

D

D

X S Y

↑ Top of heap

↑ Top of stack

4. หลังคําสัง่ new (D) Reserved By System

Programs And procedures

P Operating Q system R

5. หลังคําสัง่ new (D) Reserved By System

Programs And procedures

D

P Operating Q system R


"* 6. หลังจากเสร็จสิน้ การประมวลผลของโพรซีเจอร B (ตัวแปร X, Y จะถูก Pop ออกจาก สแตก ) Reserved By System

Programs And procedures

S D

D

D ↑ Top of heap

P Operating Q system R

↑ Top of stack

ขอสังเกต ถาเราเรียกใชตัวแปรแบบไดนามิกและเราไมไดทําการ dispose เมื่อไมตองการใชแลว (เชน เราออกจากโพรซีเจอร B แลว ) เนื้อที่ใน heap ก็จะเสียไปไมสามารถนํามาใชไดอีก 7. หลังจากเสร็จสิน้ การประมวลผลของโพรซีเจอร A (ตัวแปร S จะถูก pop ออกจากสแตก) Reserved By System

Programs And procedures

D

D

D

P Operating Q system R

↑ Top of heap

↑ Top of stack

8. หลังจากเสร็จสิน้ การประมวลผลของโปรแกรม Main (ตัวแปร P, Q, R จะถูก pop ออกจากสแตก) Reserved By System

Programs And procedures

D

D

D ↑ Top of heap

Operating system ↑ Top of stack

กิจกรรม 5.5 การสรางสแตกคู จงสรางสแตกคูดวยอะเรย โดยใหมีขอ กําหนดของสแตกเหมือนเดิม แตพารามิเตอรของการดําเนิน งานทั้ง 6 จะเปลีย่ นไปดังนี้ TYPE

StackNo = 1..2;

PROCEDURE

Create;

PROCEDURE

Push (E : StdElement; S : StackNo);

PROCEDURE

Pop (Var E : StdElement; S : StackNo);


"! FUNCTION

Empty (S : StackNo) : boolean;

PROCEDURE

Clear (S : StackNo);

เรื่องที่ 5.2.2 การใชสแตกในกระบวนการเรียกใชโพรซีเจอรหรือฟงกชัน (และรีเคอรชน่ั ) จากตัวอยางในเรื่องที่ 5.2.1 กอนหนานีเ้ ราจะเห็นสถานะของสแตกในการเรียกใชโพรซีเจอรเปนดังนี้ (M คือ Main, A คือ โพรซีเจอร A, B คือ โพรซีเจอร B) B M ณ เวลาที่ตําแหนง

1

A

A

A

M

M

M

3

6

2

M 7

8

ณ เวลาที่ตําแหนง 2 เมือ่ มีการเรียกใช A จะมีการ push คาตางๆ ทีจ่ าํ เปนสําหรับ A ซึง่ เราเรียกวา activation record ของ A ไดแก ตําแหนงของคําสั่งใน M ที่เรียกใช A เพื่อที่จะกลับไปทําคําสั่งตอไปใน M ไดเมื่อทําคําสั่งใน A เสร็จแลว และคาของตัวแปรใน A เปนตน ในระหวางที่ประมวลผล A อาจจะมีการเรียกใช B เชน ณ เวลาที่ตําแหนง 3 ก็จะมีการ push activation record ของ B ลงในสแตกซึง่ activation aecord ของ B ก็จะมีคาตางๆ ที่จําเปน ไดแก ตําแหนงของคําสั่งใน A ที่เรียกใช B และคาของตัวแปรใน B เปนตน เมือ่ เสร็จสิน้ การประมวลผลของ A ณ เวลาที่ตําหนง 7 จะมีการ pop ขอมูลของ M (activation record ของ M ) ออกจากสแตกเปนอันเสร็จสิน้ ตัวอยางของ activation record ของโพรซีเจอรหรือฟงกชันแบบรีเคอชัน (recursion) ลองพิจารณาฟงชันเพือ่ คํานวณคาแฟกตอเรียล (Factorial) ดังนี้ FUNCTION Factorial (N : integer) : integer; BEGIN IF N = 0 THEN Factorial := 1 ELSE Factorial := N * Factorial(N - 1) END; BEGIN {Main} P := Factorial (3); END;

ให F แทน Factorial, M แทน Main สถานะของสแตกในการประมวลผลดังแสดลในภาพประกอบ 5.1


"# F(0) F=1 F(1)

F(1)

F(1)

F=1*F(0)

F=1*F(0)

F=1*F(0)

F(2)

F(2)

F(2)

F(2)

F(2)

F=2*F(1)

F=2*F(1)

F=2*F(1)

F=2*F(1)

F=2*F(1)

F(3)

F(3)

F(3)

F(3)

F(3)

F(3)

F(3)

F=3*F(2)

F=3*F(2)

F=3*F(2)

F=3*F(2)

F=3*F(2)

F=3*F(2)

F=3*F(2)

M

M

M

M

M

M

M

M

M

P=F(3)

P=F(3)

P=F(3)

P=F(3)

P=F(3)

P=F(3)

P=F(3)

P=F(3)

p=6

ภาพประกอบ 5.1 การประยุกตใชสแตกสําหรับรีเคอรชั่น เรื่องที่ 5.2.3 การตรวจสอบอักขระสมดุล (Balancing Symbol) ผูที่มีประสบการณในการเขียนโปรแกรมมาแลว จะพบวาสิ่งที่เรามักจะหลงลืมเมื่อเขียนโปรแกรม และทําใหเกิดขอผิดพลาดอยูบ อ ย ๆ คือ การหลงลืมอักขระสมดุล เชน { คูก บั }, [ คูก บั ], ( คูก บั ) เปนตน ซึง่ ในการตรวจสอบอักขระสมดุลนัน้ คอมไพเลอรนําชนิดขอมูลแบบสแตกมาประยุกตใชได โดยมีวิธีการดังนี้ ใหอานอักขระทีละตัว 1. ถา อักขระเปนอักขระเปด เชน {, [, (, เปนตน ให Push ลงสแตก 2. ถา อักขระเปนอักขระปด เชน }, ], ), เปนตน ใหตรวจสอบวาอักขระบน Top ของสแตกเปน อักขระเปดทีค่ กู นั หรือไม ถาใช ให Pop อักขระนัน้ ออกจากสแตก แตถาไมใช แสดงผล error 3. เมือ่ อานอักขระหมดแลว แตสแตกไมเปนสแตกวางใหแสดงผล error เรื่องที่ 5.2.4 การคํานวณคาของนิพจนเลขคณิต (Arithmetic Expression ) โดยทั่วๆ ไปทางคณิตศาสตร เรามักนิยมเขียนนิพจนเลขคณิตในลักษณะที่เรียกวา สัญกรณเติม กลาง (infix notation) คือตัวดําเนินการ (operator) จะอยูตรงกลางของตัวถูกดําเนินการ (operand) ดังรูป operand

operator

operand

ตัวดําเนินการ ก็คอื เครื่องหมายทางคณิตศาสตร สําหรับการคํานวณตางๆ เรียงตามลําดับการ ดําเนินการกอน-หลัง (precedence) ไดแก ยกกําลัง

^

คูณ หาร

*,/

บวก ลบ

+,-


"" ถาเครือ่ งหมายมีลาํ ดับการดําเนินการเดียวกัน จะเลือกดําเนินงานของเครื่องหมายจากซายไปขวา และถามีวงเล็บจะดําเนินงานสิง่ ทีอ่ ยูใ นวงเล็บกอน ในการคํานวณนิพจนเลขคณิตดวยคอมพิวเตอร คอมพิวเตอรจะทําการแปลงนิพจนที่เขียนแบบสัญ กรณเติมกลาง ใหเปนแบบสัญกรณเติมหลัง (postfix notation) กอน คือ จะอยูในรูปแบบที่ตัวดําเนินการ (operator) อยูหลัง เชน A+B

---->

AB+

A-B

---->

AB-

A*B

---->

AB*

A/B

---->

AB/

A^B

---->

AB^

ชนิดขอมูลแบบสแตกไดนํามาใชในการเปลี่ยนนิพจนในรูปแบบของสัญกรณเติมกลาง ใหเปนสัญ กรณเติมหลัง และนํามาใชในการหาคาของนิพจนนั้นๆ ดวย ดังรายละเอียดในวิธกี าร (algorithm) ดังตอไป นี้ วิธีการเปลี่ยนนิพจนแบบเติมกลางใหเปนแบบเติมหลัง 1. อานคาตัวอักขระของนิพจน ซึง่ อักขระนีจ้ ะเปนไดดงั กรณีตอ ไปนี้ - เปนตัวถูกดําเนินการ (operand), - เปนวงเล็บเปด ”(“, - เปนวงเล็บปด”)”, 2. เปนตัวดําเนินการ (operator) 3. IF ตัวอักขระเปน operand THEN ใหแสดงผลลัพธตัวอักขระนั้น ELSE ตัวอักขระอาจจะเปนวงเล็บหรือ operator 4. IF สแตกวาง THEN Push ตัวอักขระลงบนสแตก ELSE สแตกไมวาง IF ตัวอักขระเปน “(“ THEN Push ตัวอักขระลงบนสแตก ELSE ตัวอักขระเปน “)” หรือ operator 5. IF ตัวอักขระ เปน “)” THEN PoP สิ่งที่อยูบนสแตกจนกระทั่งพบ “(“ และ pop ออกมาดวย ELSE ตัวอักขระเปน operator (สิ่งที่อยูบนสแตก “(“ มี priority ต่าํ สุด) 6. IF priority (ตัวอักขระ) > priority (สิ่งที่อยูบนสแตก) THEN Push ตัวอักขระลงบนสแตก ELSE Pop สิง่ ทีอ่ ยูบ นสแตกออกจนกระทัง่ Priority (ตัวอักขระ) > priority (สิ่งที่อยูบนสแตก) Push ตัวอักขระลงบนสแตก


%$$ 7. กลับไปที่ 1 และทําจนกระทั่งหมดขอมูล 8. Pop สิ่งที่อยูในสแตกออกมา หมายเหตุ 1. สิ่งที่อยูในสแตกจะมีเฉพาะเครื่องหมายการกระทํา ( + , - , * , / ,^) และวงเล็บเปด “(“ เทานัน้ 2. ถาตัวอักขระเปน operand จะเขียน ตัวอักขระนัน้ ออกมาทันที 3. ถา Pop operator ออกจากสแตกใหเขียน operator นัน้ ดวย แตถา Pop วงเล็บเปด “(“ ไมตอง เขียน ถาเราใชวิธีดังกลาวขางตนกับนิพจน ((A+B)*C/D+E^F)/G จะเปนดังนี้ 1

1

1

1

1

1

1

1

0

1

2

3

4

5

6

7

8

)

/

G

/

/

ลําดับ

1

2

3

4

5

6

7

8

ขอมูล

(

(

A

+

B

)

*

C /

D +

E

^

F

Top

(

(

(

+

+

(

*

*

/

/

+

+

^

^

(

(

(

(

(

(

(

(

(

(

+

+

(

(

(

(

สแตก ผลลัพธ

A

B

+

9

1

C *

D /

E

F

^ +

ขั้นตอนการคํานวณคานิพจนแบบสัญกรณเติมหลัง 1. อานคาตัวอักขระของนิพจนจากซายไปขวา 2. IF ตัวอักขระเปน operand THEN Push ตัวอักขระลงบนสแตก ELSE ตัวอักขระเปน operator Pop สิ่งที่อยูบนสแตก 2 ตัว มาดําเนินการตาม opeartor ของตัวอักขระนั้น ๆ Push ผลลัพธทไ่ี ดลงบนสแตก

G /


%$% 3. กลับไปที่ 1 และทําจนกระทั่งหมดขอมูล 4. Pop สิง่ ทีอ่ ยูใ นสแตกออกมาจะเปนผลลัพธ


%$&

1

ลําดับ A

ขอมูล A

2

B

สแตก B A

3

+

A+B

4

C

C A+B

5

*

(A+B)*C

6

D

D (A+B)*C

7

/

((A+B)*C)/D

8

E

E ((A*B)*C)/D

9

F

F E ((A+B)*C)/D

10

^

(E^F) ((A+B)*C)/D

11

+

(((A+B)*C)/D)+(E^F)

12

G

G (((A+B*C)/D)+(E^F)

13

/

((((A+B)*C)/D)+(E^F))/G

data structure lesson05  

แผนการสอนประจําบทเรียน หัวขอของเนื้อหา รายชื่ออาจารยผูจัดทํา สุณี รักษาเกียรติศักดิ์ เอกสารประกอบการสอน 1. เอกสารชุดวิชา #% ประเมินผล 1....

Advertisement