data structure lesson02

Page 1

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

การสรางชนิดขอมูลแบบคัดยอ

เรือ่ งที่ 2.1.2

การใชชนิดขอมูลแบบคัดยอ

ตอนที่ 2.2 มาตรวัดประสิทธิภาพของอัลกอริทึม (1 คาบ) เรือ่ งที่ 2.2.1

แนวคิด

เรือ่ งที่ 2.2.2

การนับจํานวนครั้งของการใชงานคําสั่ง

เรือ่ งที่ 2.2.3

คําสัง่ มาตรเวลา

เรือ่ งที่ 2.2.4

การวิเคราะหเชิงเสนกํากับ

เรือ่ งที่ 2.2.5

สัญกรณโอใหญ

เรือ่ งที่ 2.2.6

ตัวอยางการวิเคราะหโปรแกรมเชิงเสนกํากับ

แนวคิด 1. ในตอนที่ 1.3 ของบทเรียนที่ 1 เราไดเห็นหลักการของการสรางชนิดขอมูลตามความตองการ ของเรา โดยใชหลักการของชนิดของขอมูลแบบคัดยอ ซึง่ มีวธิ กี ารดําเนินการ 2 ขั้นตอนใหญๆ ขั้นตอนแรกคือ การกําหนดคุณลักษณะเฉพาะของชนิดของขอมูลทีเ่ ราตองการสรางใหชดั เจน และขั้นตอนที่ 2 คือการสรางชนิดขอมูลตามคุณลักษณะเฉพาะทีก่ าํ หนด โดยในตอนที่ 1.3 ของบทเรียนที่ 1 ไดใหตัวอยางคุณลักษณะเฉพาะของชนิดขอมูลที่ตองการสราง 2 ชนิด คือ ชนิดขอมูล “Color” และชนิดขอมูล “LetterString” 2. ในตอนที่ 2.1 ของบทเรียนที่ 2 นี้ จะไดนาํ เสนอวิธใี นการสรางชนิดขอมูล “Color” และ “LetterString” ตามคุณลักษณะเฉพาะทีก่ าํ หนดในตอนที่ 1.3 ของบทเรียนที่ 1 โดยใช UNIT ของ Turbo Pascal เปนเครือ่ งมือ พรอมทั้งเขียนโปรแกรมเพื่อทดสอบวาชนิดขอมูลที่เราสราง ขึน้ สามารถทํางานไดถกู ตอง 3. ประสิทธิภาพของการดําเนินงานทีส่ ราง ขึ้นอยูกับการแทนที่ขอมูลที่เลือกใชและอัลกอริทึมใน สราง ซึ่งมาตรวัดอันหนึ่งที่นิยมใชในการวัดประสิทธิภาพของอัลกอริทึม คือ สัญกรณโอใหญ (function big O)


24 วัตถุประสงค หลังจากศึกษาบทเรียนที่ 2 แลว นักศึกษาสามารถ 1. เห็นตัวอยางและเขาใจวิธีการสรางและการทดสอบการใช ชนิดขอมูลแบบคัดยอ และสามารถ ประยุกตใชได 2. เขาใจการทํางานของมาตรวัดประสิทธิภาพของอัลกอริทึมได กิจกรรมการเรียนการสอน กิจกรรมทีน่ กั ศึกษาตองทําสําหรับการเรียนการสอน ไดแก 1. ศึกษาเอกสารชุดวิชา/โฮมเพจชุดวิชา ตอนที่ 2.1 และตอนที่ 2.2 2. ทํากิจกรรมของบทเรียนที่ 2 3. ทําแบบประเมินผลของบทเรียนที่ 2 เอกสารประกอบการสอน 1. เอกสารชุดวิชา สื่อการสอน 1. โฮมเพจชุดวิชา 2. สไลดประกอบการบรรยาย (Powerpoint) 3. โปรแกรมคอมพิวเตอร ประเมินผล 1. ประเมินผลจากกิจกรรมที่ทํา 2. ประเมินผลจากคําถามทายบทเรียน


25 ตอนที่ 2.1 การสรางและการใชขอมูลแบบคัดยอ หัวเรื่อง เรือ่ งที่ 2.1.1

การสรางชนิดขอมูลแบบคัดยอเชิงเดีย่ ว Color

เรือ่ งที่ 2.1.2

การใชชนิดขอมูลแบบคัดยอเชิงเดี่ยว Color

เรือ่ งที่ 2.1.3

การสรางชนิดขอมูลแบบคัดยอเชิงโครงสราง LetterString

เรือ่ งที่ 2.1.4

การใชชนิดขอมูลแบบคัดยอเชิงโครงสราง LetterString

แนวคิด 1. หลักการสรางชนิดขอมูลตามความตองการของเรา โดยใชหลักการของชนิดของขอมูลแบบคัด ยอ มีวธิ กี ารดําเนินการ 2 ขั้นตอนใหญ ๆ ขั้นตอนแรกคือ การกําหนดคุณลักษณะเฉพาะของ ชนิดของขอมูลที่เราตองการสรางใหชัดเจน และขั้นตอนที่ 2 คือการสรางชนิดขอมูลตามคุณ ลักษณะเฉพาะทีก่ าํ หนด 2. UNIT ของ Turbo Pascal สามารถใชเปนเครื่องมือในการสรางชนิดขอมูลแบบคัดยอตามคุณ ลักษณะเฉพาะทีก่ าํ หนดไวแลว เมื่อสรางแลวเราตองเขียนโปรแกรมเพื่อทดสอบวาชนิดขอมูลที่ เราสรางขึน้ สามารถทํางานไดถกู ตอง วัตถุประสงค หลังจากที่ศึกษาตอนที่ 2.1 แลว นักศึกษาสามารถ 1. เห็นตัวอยางและเขาใจวิธีการสรางและการทดสอบการใชชนิดขอมูลแบบคัดยอ ชนิด “Color” และชนิด “LetterString” 2. สามารถประยุกตวธิ กี ารไปใชได ในการสรางและทดสอบชนิดขอมูลแบบอืน่ ๆ เรื่องที่ 2.1.1 การสรางชนิดขอมูลแบบคัดยอ การสรางชนิดขอมูลแบบคัดยอเชิงเดี่ยว Color ตามคุณลักษณะเฉพาะที่กําหนดของชนิดขอมูลแบบคัดยอ “Color” ในเรื่องที่ 1.3.1 ของบทเรียนที่ 1 นัน้ หากเราตองการจะสรางชนิดขอมูล “Color” โดยใช Turbo Pascal เปนเครือ่ งมือ เราจะตองนึกถึงการ ดําเนินการ 2 สวน สวนที่ 1 คือ การเลือกการแทนทีข่ อ มูลของ domain ของ Color ซึ่งเราอาจจะใชขอมูล ชนิด enumerated ในภาษาปาสคาลได เมือ่ เลือกการแทนทีข่ อ มูลแลว เราก็สามารถจะสรางการดําเนินงาน ตาง ๆ ตามทีร่ ะบุในคุณลักษณะเฉพาะของ “Color” ได ดังตัวอยางของโปรแกรม 2.1


26 คําอธิบายโปรแกรม 2.1 UNIT ในปาสคาลจะแบงเปนสองสวน สวนแรกเราเรียกวาสวนของ INTERFACE ซึง่ ก็คอื สวนทีจ่ ะ ติดตอกับผูใช (สวนซึ่งผูใชมองเห็น) ซึ่งประกอบดวยการแทนที่ขอมูลซึ่งในที่นี้ คือ Color ในบรรทัดที่ 5 และ การดําเนินงานทีส่ ามารถทําไดกบั Color ไดแก Mix, Primary, Form ในบรรทัดที่ 6, 7, 8 ตามลําดับ สวนที่ สองเราเรียกวาสวนของ IMPLEMENTATION จะเปนสวนรายละเอียดของการสรางการดําเนินงานซึง่ สวนนีจ้ ะ เปนสวนที่ผูใชจะมองไมเห็น (information hiding) ในหลักการของขอมูลแบบคัดยอนั้นจริง ๆ แลวการแทนที่ขอมูลควรจะเปนสวนที่ซอนจากผูใชดวย แต UNIT ของ TURBO PASCAL ยังไมสามารถซอนจากผูใชไดเพราะกําหนดอยูในสวนของ INTERFACE ทํา ใหยังไมาสามารถสนับสนุนคุณสมบัติของ integrity ไดอยางสมบูรณ ภาษาโปรแกรมในยุคที่ 3 ทีส่ นับสนุน การทํางานของหลักการของขอมูลแบบคัดยอคือภาษา Ada การสรางชนิดขอมูลแบบคัดยอเชิงโครงสราง Letterstring เราสามารถสรางชนิดขอมูลแบบคัดยอ Letterstring ไดดว ยวิธกี ารทํานองเดียวกันกับการสรางชนิด ขอมูลแบบคัดยอ Color นัน่ คือ การเลือกการแทนทีข่ อ มูลของ Letterstring ซึ่งอาจจะใชแถวลําดับหรืออะ เรยกไ็ ด หลังจากนัน้ ก็สรางการดําเนินงานตาง ๆ ของ Letterstring กิจกรรม 2.1 ฝกการสรางชนิดขอมูลแบบคัดยอ 1. จงคอมไพล UNIT ColorU ตามตัวอยาง และตั้งชื่อไฟลชื่อ ColorU.pas เมือ่ คอมไพลแลวและ ไมเกิด error ระบบจะสราง object code ไฟลชื่อ ColorU.TPU ใหในไดเร็กทอรีเดียวกับ ColorU.pas 2. จงสราง UNIT StingU ตามคุณลักษณะเฉพาะ 2.2 และตั้งชื่อไฟลชื่อ StringU.pas


27 UNIT ColorU; 1 {**************************} 2 INTERFACE 3 {**************************} 4 TYPE Color=(Red,Blue,Yellow,Green,Violet,Orange); 5 FUNCTION Mix(C1,C2:Color):Color; 6 FUNCTION Primary(C:Color):boolean; 7 PROCEDURE Form(C:Color;VAR C1,C2:Color); 8 {**************************} 9 IMPLEMENTATION 10 {**************************} 11 FUNCTION Mix(C1,C2:Color):Color; 12 BEGIN 13 IF ((C1=Red)and(C2=Yellow))or((C1=Yellow)and(C2=Red)) THEN 14 Mix:=Orange 15 ELSE IF ((C1=Red)and(C2=Blue))or((C1=Blue)and(C2=Red)) THEN 16 Mix:=Violet 17 ELSE IF ((C1=Yellow)and(C2=Blue))or((C1=Blue)and(C2=Yellow))18 THEN Mix:=Green 19 END; 20 21 FUNCTION Primary(C:Color):boolean; 22 BEGIN 23 IF (C=Red)or(C=Yellow)or(C=Blue) THEN Primary:=True 24 ELSE Primary:=False; 25 26 END; 27 28 PROCEDURE Form(C:Color;VAR C1,C2:Color); 29 BEGIN 30 IF C=Orange THEN 31 BEGIN 32 C1:=Red; C2:=Yellow; 33 END 34 ELSE IF C=Green THEN 35 BEGIN 36 C1:=Yellow; C2:=Blue; 37 END 38 ELSE IF C=Violet THEN 39 BEGIN 40 C1:=Red; C2:=Blue; 41 END; 42 END; 43 44 END. 45

โปรแกรม 2.1 การสรางขอมูลแบบคัดยอชนิด “Color”


28 เรื่องที่ 2.1.2

การใชชนิดขอมูลแบบคัดยอเชิงเดี่ยว Color

UNIT เปรียบเสมือนชนิดขอมูลทีเ่ ราสรางขึน้ มาเปน library และผูอ น่ื สามารถนําไปใชได ดังนัน้ เพือ่ ใหแนใจวา UNIT ทีเ่ ราสรางขึน้ มาถูกตอง เราตองมีการทดสอบ (ซึง่ เปรียบเสมือนเปนผูใ ช) ดังนั้นผูใชเพียง แตทราบวาชนิดขอมูลคัดยอที่สรางมานี้มีชนิดเปน Color ซึง่ เปน enumerated type ประกอบดวยขอมูล 6 ตัว คือ Red, Blue,Yellow,Green,Violet,Orange และมีการดําเนินงานใหใชได 3 การดําเนินงานคือ Mix, Primary, และ Form ซึ่งมีรูปแบบการใชดังปรากฎในบรรทัดที่ 6, 7, 8 เงือ่ นไขและผลลัพธในการดําเนินงาน ดังทีก่ าํ หนดไวในคุณลักษณะเฉพาะ ผูใชสามารถเรียกการดําเนินงานทั้งสามนี้ไปใชได โดยไมตองสนใจใน รายละเอียดวาการดําเนินงานเหลานีส้ รางมาไดอยางไร (mplementation independence) ตัวอยางโปรแกรมการทดสอบการดําเนินงานดังแสดงในโปรแกรม 2.2 PROGRAM ColorT; USES ColorU,wincrt; VAR C,C1,C2:Color; CS,CS1,CS2:string; Choice:char; PROCEDURE GetChoice(VAR Ch:char); BEGIN write('Input choice of operation: '); readln(Ch); END; PROCEDURE ConvertColor(S:string;VAR C:Color); BEGIN IF S='red' THEN C:=Red ELSE IF S='yellow' THEN C:=Yellow ELSE IF S='blue' THEN C:=Blue ELSE IF S='green' THEN C:=Green ELSE IF S='orange' THEN C:=Orange ELSE IF S='violet' THEN C:=Violet ELSE writeln('Invalid Color, please primary color again'); END; FUNCTION WriteColor(C:Color):string; BEGIN IF C=Red THEN WriteColor:='red' ELSE IF C=Yellow THEN WriteColor:='yellow' ELSE IF C=Blue THEN WriteColor:='blue' ELSE IF C=Green THEN WriteColor:='green' ELSE IF C=Orange THEN WriteColor:='orange' ELSE IF C=Violet THEN WriteColor:='violet'; END; BEGIN

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


29 Clrscr; writeln('****************************'); writeln('Test operations of ADT Color'); writeln('****************************'); writeln('1 Mix'); writeln('2 Primary'); writeln('3 Form'); writeln('9 Quit'); writeln('******************************************'); writeln('All possible colors that can be input are:'); writeln('red, yellow, blue, green, orange, violet'); writeln('******************************************'); Getchoice(Choice); WHILE (Choice<>'9') DO BEGIN CASE Choice OF '1' : BEGIN write('Input primary color1 : '); readln(CS1); write('Input primary color2 : '); readln(CS2); ConvertColor(CS1,C1); ConvertColor(CS2,C2); C:=Mix(C1,C2); CS:=WriteColor(C); writeln('The result of mixing ', CS1, ' and ', CS2, ' is ', CS); END; '2' : BEGIN write('Input color : '); readln(CS); ConvertColor(CS,C); IF Primary(C) THEN writeln(CS, ' is a primary color') ELSE writeln(CS, ' is not a primary color'); END; '3' : BEGIN write('Input a non primary color : '); readln(CS); ConvertColor(CS,C); Form(C,C1,C2); CS1:=WriteColor(C1); CS2:=WriteColor(C2); writeln(CS1, ' and ',CS2,' are two primary colors that form the input color', CS); END; ELSE BEGIN writeln('Not a correct choice, try again'); GetChoice(Choice);

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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84


30 END; END {CASE}; writeln('******************************************'); GetChoice(Choice); END {WHILE}; writeln('!!! End of program !!! '); END.

85 86 87 88 89 90 91 92 93 94 95

โปรแกรม 2.2 การทดสอบการใชขอมูลแบบคัดยอชนิด “Color” คําอธิบายโปรแกรม 2.2 1. เมือ่ มีการเรียกใช UNIT ColorU ในบรรทัดที่ 2 ชื่อ (identifier) ของ UNIT ColorU ที่โปรแกรม ColorT จะรูจักและเรียกใชไดทันที คือ Color, Mix, Primary, และ Form 2. เนื่องจากในการทดสอบนี้จะใหมีการรับขอมูลจากคียบอรด ซึ่งขอมูลที่มีชนิดเปน Color เปน ชนิดแบบ enumerated ซึง่ ไมสามารถรับคาจากคียบ อรดได จึงตองใหมีการรับคาเปน string แลวใชโพรซี เจอร ConvertColor แปลงชนิด string เปน Color 3. ในทํานองเดียวกันเนือ่ งดวยเราไมสามารถแสดงผลขอมูลชนิด enumerated ดวยคําสัง่ write หรือ writeln ได เราจึงตองมีการแปลงขอมูลจากชนิด Color ไปเปน string ดวยฟงกชัน WriteColor 4. ในโปรแกรมนี้มีการเรียกใชการดําเนินงานของ ADT Color ฟงกชัน Mix ในบรรทัดที่ 58, ฟงกชัน Primary ในบรรทัดที่ 67, โพรซีเจอร Form ในบรรทัดที่ 76 กิจกรรม 2.2 ฝกการทดสอบการใชงานขอมูลแบบคัดยอ 1. จงคอมไพลและรันโปรแกรม ColorT ตามตัวอยาง และตั้งชื่อไฟลชื่อ ColorT.pas และศึกษาตร รกการทํางานของโปรแกรม 2. จงสรางการดําเนินงานขึน้ อีก 1 การดําเนินงานคือ Assign ใน UNIT ColorU และจงทดสอบการ ดําเนินงาน Assign ในโปรแกรม ColorT ดวย 3. จงเขียนโปรแกรม StringT เพื่อทดสอบการใชงานชนิดขอมูล LetterString และตั้งชื่อไฟลชื่อ StringT.pas


31 ตอนที่ 2.2 การวิเคราะหเชิงเสนกํากับและสัญกรณโอใหญ หัวเรื่อง เรือ่ งที่ 2.2.1

แนวคิด

เรือ่ งที่ 2.2.2

การนับจํานวนครั้งของการใชงานคําสั่ง

เรือ่ งที่ 2.2.3

คําสัง่ มาตรเวลา

เรือ่ งที่ 2.2.4

การวิเคราะหเชิงเสนกํากับ

เรือ่ งที่ 2.2.5

สัญกรณโอใหญ

เรือ่ งที่ 2.2.6

ตัวอยางการวิเคราะหโปรแกรมเชิงเสนกํากับ

แนวคิด 1. การวิเคราะหประสิทธิภาพเชิงเวลา อาศัยการนับจํานวนครั้งของการใชงานคําสั่งตางๆ ใน โปรแกรม โดยเขียนจํานวนครั้งนี้เปนฟงกชันของขนาดของขอมูลขาเขา 2. การวิเคราะหจะงายขึ้น ถาพิจารณานับเฉพาะคําสั่งมาตรเวลาในโปรแกรม ซึ่งคือคําสั่งที่ถูกใช ทํางานมากที่สุดในโปรแกรม โดยเวลาการทํางานโดยรวมจะแปรโดยตรงตามจํานวนครั้งที่คําสั่ง มาตรเวลาถูกใชงาน 3. การวิเคราะหเชิงกํากับเปนการศึกษาพฤติกรรมของอัตราการเติบโตของฟงกชันเวลาการ ทํางานของโปรแกรม เมื่อขอมูลขาเขามีขนาดใหญมาก 4. เราใชแนวคิดของสัญกรณโอใหญในการแทนฟงกชันเวลาการทํางานที่ซับซอน ดวยฟงกชันที่ ซับซอนนอยกวาเพื่อใหเขาใจและงายตอการเปรียบเทียบอัตราการเติบโตของเวลาการทํางาน วัตถุประสงค หลังจากที่ศึกษาตอนที่ 2.3 แลว นักศึกษาสามารถ 1. เขาใจการวิเคราะหประสิทธิภาพเชิงเวลาของโปรแกรม 2. เขาใจวิธีการใชสัญกรณโอใหญในการวิเคราะหเวลาการทํางานของโปรแกรมเชิงเสนกํากับ เรื่องที่ 2.2.1

แนวคิด

ปญหาที่นักโปรแกรมควรถามตัวเองเสมอก็คือวา โปรแกรมที่ตนเขียนนั้นมีประสิทธิภาพเชิงเวลา การทํางานอยางไร และเมื่อเทียบกับอีกโปรแกรมที่ใชแกปญหาเดียวกันแลวเราจะรูไดอยางไรวาของใครเร็ว กวากัน คําตอบที่มักพบบอยๆ ก็คอื “ก็ลองใชงานจริงแลวจับเวลาดูจริงๆ กันเลยก็จะรูเ อง” ปญหาของการ ลองใชงานจริงเลย จะอยูตรงที่วาแลวจะใชชุดขอมูลขาเขาใดเปนชุดทดสอบ และเราจะทราบไดอยางไรวาชุด ขอมูลตางๆ ที่นํามาทดสอบนั้นครอบคลุมจุดเดนจุดดอยของโปรแกรมที่เขียนขึ้น


32 การวิเคราะหการทํางานเชิงเวลาโดยทั่วไปอาศัยการนับจํานวนครั้งของการใชงานคําสั่งตางๆ ใน โปรแกรมระหวางการทํางาน ซึ่งเขียนบรรยายจํานวนครั้งที่นับไดนี้ใหเปนฟงกชันของขนาดของขอมูลขาเขา ของปญหา อัตราการเติบโตของฟงกชันนี้เองจะสะทอนใหเห็นถึงแนวโนมการเพิ่มของเวลาการทํางานเมื่อ ขนาดของขอมูลเพิ่มขึ้นวามีลักษณะอยางไร โดยเรามักวิเคราะหเวลาการทํางานสําหรับขอมูลขาเขากรณีเลว สุด (worst case) และกรณีเฉลีย่ (average case) เพื่อใหการวิเคราะหกระทําไดงายขึ้น โดยทั่วไปจะอาศัยวิธีการนับเฉพาะ “คําสัง่ มาตรเวลา” ตางๆ ซึง่ คือคําสัง่ ทีจ่ ะทํางานเปนจํานวนครัง้ ไมนอ ยกวาคําสัง่ อืน่ ๆ ดังนั้นจึงใชเปนตัวแทนเพื่อศึกษาแนวโนมของ เวลาการทํางานโดยรวมได และยังอาศัยการวิเคราะหเชิงเสนกํากับ (asymptotic analysis) โดยใชสัญกรณ เชิงเสนกํากับโอใหญ (Big O) ในการแทนฟงกชัน เพื่อลดรูปฟงกชันใหสามารถตีความไดงายขึ้น อีกทั้งชวย จัดการวิเคราะหไดงา ยขึน้ ดวย ซึง่ จะไดนาํ เสนอในรายละเอียดตอไป เรื่องที่ 2.2.2

การนับจํานวนครั้งของการใชงานคําสั่ง

วิธีหนึ่งที่ใชในการวิเคราะหเชิงเวลาคือการหาผลรวมของเวลาการทํางานของคําสั่งตางๆ ใน โปรแกรมซึ่งถูกใชงาน ลองดูตัวอยางโปรแกรมสั้นๆ ขางลางนี้ กําหนดใหเวลาการทํางานของคําสั่งในบรรทัด ที่ i เปน ti วินาที 01: function sum( var x : vector; n : integer ) : integer; 02: var i, s : integer; 03: begin 04: s := 0; 05: for i:=1 to n do 06: s := s + x[i]; 07: sum := s; 08: end; sum ทําหนาทีห ่ าผลรวมของจํานวนในเวกเตอร

x (ซึง่ สรางดวยแถวลําดับ) ตั้งแตชองที่ 1 ถึง n โดย

ใชเวลารวมทั้งสิ้นเทากับ n

t1 Ι t 2 Ι t 3 Ι t 4 Ι

¦ Φt5 Ι t 6 Γ Ι t5 Ι t 7 Ι t8 i [1

นักศึกษาอาจรูส กึ ตอนนีว้ า ถึงแมวาสามารถเขียนออกมาไดดังแสดงขางบนนี้ แลวสรุปไดวา อะไร เพราะเวลาการทํางานก็ยงั ขึน้ กับคา ti ทัง้ หลายในนิพจน ตองขอบอกตอนนีเ้ ลยวาจุดประสงคของการ วิเคราะหประสิทธิภาพเชิงเวลาก็เพื่อวิเคราะหใหเห็นแนวโนมของเวลาการทํางานของโปรแกรมเมื่อขนาดของ ขอมูลเพิ่มขึ้น นั่นคือทําใหเราประมาณไดวาถาขอมูลเพิ่มขึ้น k เทาแลวเวลาการทํางานจะเพิ่มเทาไร กําหนดให ti ℑ c1 สําหรับทุกๆ i หมายความวาให c1 เปนคาคงตัวซึง่ มีคา เทากับเวลาการทํางาน ของคําสัง่ ทีท่ าํ งานนานสุดในโปรแกรม ดังนัน้ จากตัวอยางเวลาการทํางานทีแ่ สดงขางบนนี้ เราสามารถลดรูป ใหแลดูกระทัดรัดขึน้ ไดเปน n

t1 Ι t 2 Ι t 3 Ι t 4 Ι

n

¦ Φt5 Ι t 6 Γ Ι t5 Ι t 7 Ι t8 ℑ 4c1 Ι ¦ 2c1 Ι 3c1 i [1

i [1 [ c1 Φ2n Ι 7 Γ

สรุปไดวา sum ใชเวลาการทํางานไมเกิน c1 (2n + 7) ซึ่งเปนฟงกชันแปรผันโดยตรงแบบเชิงเสนกับ n


33 ตองขอเนนวาการทีเ่ รากําหนดให "c1 เปนคาคงตัวมีคาเทากับเวลาการทํางานของคําสั่งที่ทํางาน นานสุดในโปรแกรม" ในการวิเคราะหขางบนนี้ คําสั่งตางๆ ที่ใชจะตองเปนคําสั่งซึ่งใชเวลาการทํางานไมแปร ตามจํานวนขอมูล เรียกวาเปนคําสัง่ มูลฐานซึง่ คือคําสัง่ งายๆ เชน บวก ลบ คูณ หาร เปรียบเทียบ หรืออืน่ ๆ ที่ ใชเวลาไมแปรตามจํานวนขอมูล ถึงตรงนี้บางคนอาจสงสัยวาการบวกก็ใชเวลาแปรตามจํานวนบิต ซึง่ ก็เปน ความเขาใจที่ถูกตอง แตเนื่องจากในที่นี้เราใชการบวกขอมูลแบบ integer ซึ่งจํานวนหนึ่งๆ มีขนาดจํากัด เชน 16 บิต จึงถือไดวาใชเวลาคงตัว เพราะบวกอยางไรก็ไมเกิน 16 บิต การวิเคราะหเชิงเวลาทีก่ ระทํามานัน้ อาจดูคลายการนับจํานวนครัง้ ทีค่ าํ สัง่ มูลฐานตางๆ ในโปรแกรม ถูกเรียกใชงาน จากตัวอยาง คําสั่งตางๆ ใน sum ทํางานเปนจํานวน 2n + 7 ครัง้ แตละครั้งใชเวลาไมเกิน c1 ไดผลรวมเปน c1(2n + 7) การนับจํานวนครัง้ ทีค่ าํ สัง่ มูลฐานตางๆ ในโปรแกรมถูกเรียกใชงานนี่เองจึงเปนกล วิธีหลักในการวิเคราะหประสิทธิภาพเชิงเวลา มาดูอกี สักตัวอยาง matrixMult ขางลางนี้มีหนาที่หาผลคูณของเมทริกซ x และ y ซึ่งมีขนาด n∑n ไดผลลัพธเก็บไวในเมทริกซ z (ในทีน่ เ้ี ราสรางเมทริกซตา งๆ ดวยแถวลําดับสองมิต)ิ 01: procedure matrixMult( var x, y, z : matrix; n : integer ); 02: var i, j, k : integer; 03: begin 04: for i:=1 to n do 05: for j:=1 to n do 06: z[i,j] := 0.0; 07: for i:=1 to n do 08: for j:=1 to n do 09: for k:=1 to n do 10: z[i,j] := z[i,j] + x[i,k]*y[k,j]; 11: end;

นับจํานวนครั้งที่แตละคําสั่งถูกใชงานจะไดดังตารางขางลางนี้ บรรทัดที่ จํานวนครั้งที่ทํางาน 1 2 3 4 5 6 7 8 9 10 11

1 1 1 n+1 n(n+1) n2 n+1 n(n+1) n2(n+1) n3 1

รวมจํานวนครั้งของการทํางานของคําสั่งในแตละบรรทัดเขาดวยกัน และคูณกับ c2 ซึ่งกําหนดใหเปน เวลาการทํางานของคําสัง่ ทีท่ าํ งานนานสุดในโปรแกรม จะไดวาเวลาการทํางานของโปรแกรมนี้ไมเกิน c2⌡ ( 2n3 + 4n2 + 4n + 6 )

ถากลับไปดูทต่ี วั matrixMult อีกทีหนึ่ง หลายคนอาจรูสึกวานาจะยุบรวมวงวน for ทีซ่ อ นกันสอง ชั้นในบรรทัดที่ 4 ถึง 6 ไปเปนสวนหนึ่งของวงวนขางลาง นัน่ คือยายคําสัง่ ที่ 6 ไปอยูหลังคําสั่งที่ 8 กลายเปน โปรแกรมใหมขางลางนี้


34 01: procedure matrixMult( var x, y, z : matrix; n : integer ); 02: var i, j, k : integer; 03: begin 04: for i:=1 to n do 05: for j:=1 to n do 06: begin 07: z[i,j] := 0.0; 08: for k:=1 to n do 09: z[i,j] := z[i,j] + x[i,k]*y[k,j]; 10: end; 11: end;

เมื่อวิเคราะหโปรแกรมขางบนนี้จะไดวาใชเวลาการทํางานไมเกิน c2⌡ ( 2n3 + 5n2 + 2n + 5 ) แลวอยาง นี้หมายความวาที่เขียนแบบใหมนี้ชากวาแบบเกาหรือ ? ทั้งๆ ที่แรงจูงในของการเขียนใหมนี้ ก็เพราะรูส กึ วา นาจะไดแบบที่เร็วกวา ตองขอบอกตรงนีว้ า เราคงนําผลลัพธของการวิเคราะหทง้ั สองมาเปรียบเทียบกันโดยดู ที่สัมประสิทธิ์เห็นจะลําบาก เพราะเรานับทุกบรรทัด ซึ่งแตละบรรทัดใชเวลาการทํางานตางกัน (ที่ไมเกิน c2) การคูณดวยคาคงตัว c2 ตามที่ทํามาบอกเราเพียงแคขอบเขตบนของเวลาการทํางาน (นัน่ คือบอกวาเวลาการ ทํางานไมเกินผลทีว่ เิ คราะหได) นอกจากนี้หลายคนอาจตั้งคําถามวาทําไมตองนับบรรทัดที่เปนการประกาศ ตัวแปร begin และ end ดวย ซึ่งดูเหมือนวาจะไมไดถูกแปลเปนคําสั่งเครื่องแตอยางใด การทีส่ มั ประสิทธิ์ ของพจน n2 ตางกันนิดหนอย (4 กับ 5 สําหรับตัวอยางขางตน) จึงบอกอะไรเราไมไดหรอกวาแบบใดจะเร็ว กวากัน อีกทั้งเมื่อ n มีคาเพิ่มขึ้น พจน n2 นั้นก็เปนพจนที่มีคาเพิ่มขึ้นนอยกวาคาที่เพิ่มขึ้นของพจน n3 ความ แตกตางของสัมประสิทธิ์ที่พจน n2 ยิ่งไมคอยมีผลโดยรวม สรุปไดวาเรานาใหความสนใจกับพจนที่มีการเติบ โตเร็วกวาพจนอื่นๆ และสัมประสิทธิ์ที่เปนคาคงตัวที่คูณอยูนั้นนํามาเปรียบเทียบไดไมคอยชัดเจนนักถาตาง กันไมมาก จึงเปนที่มาของกลวิธีการวิเคราะหดวยการนับคําสั่งมาตรเวลา และการวิเคราะหเชิงเสนกํากับ เพือ่ ชวยใหการวิเคราะหกระทําไดงายขึ้น เรื่องที่ 2.2.3

คําสั่งมาตรเวลา

หลายคําสั่งในโปรแกรมที่เขียนขึ้นนั้น บางคําสั่งถูกเรียกใชงานเปนจํานวนคงตัวไมขึ้นกับขนาดของ ขอมูล บางคําสั่งก็ถูกเรียกใชนอยกวาคําสั่งอื่นอยางเห็นไดชัด หมายความวาคําสั่งเหลานี้ไมไดไปมีสวนเปน ตัวกําหนดอัตราการเติบโตของเวลาการทํางานโดยรวมเอาเลย แตเราก็ตองเสียเวลาไปนับจํานวนครั้งที่มันถูก ใชงานอยูดี เพือ่ ลดภาระการนับคําสัง่ เหลานี้ กอนจะเริม่ นับ เราควรพิจารณาเสียกอนวาคําสัง่ ใดในโปรแกรม ทีเ่ ปนตัวกําหนดเวลาการทํางานโดยรวม เราเรียกคําสัง่ ประเภทนีว้ า เปนคําสัง่ มาตรเวลา (ซึ่งมีไดมากกวาหนึ่ง คําสั่งในโปรแกรม) คําสั่งมาตรเวลาเปนคําสั่งที่ถูกใชทํางานมากที่สุดในโปรแกรม นัน่ คือเวลาการทํางานโดย รวมจะแปรโดยตรงตามจํานวนครั้งที่คําสั่งมาตรเวลาถูกใชงาน จาก sum ในหัวขอที่แลวนั้น คําสัง่ for (บรรทัดที่ 5) เปนคําสั่งมาตรเวลาของโปรแกรมนี้ คําสั่งนี้ถูกเรียกใชงานเปนจํานวน n+1 ครัง้ (เนือ่ งจากเปน วงวนแบบ for ซึ่งให i เริ่มที่ 1 เพิ่มทีละหนึ่งจนกระทั่งเมื่อมีคาเทากับ n+1 จึงหลุดจากวงวน) หรือจะใชคําสั่ง ที่บรรทัดที่ 6 ภายในวงวน for ก็ได เมื่อกําหนดให n > 0 ถาเรานับเฉพาะคําสัง่ ทีบ่ รรทัดที่ 6 จะไดจํานวนครั้ง ที่ถูกเรียกใชงานเปนจํานวน n ครัง้ สรุปไดวา sum ใชเวลาการทํางานเปนฟงกชนั เชิงเสนของ n


35 ถามาดูที่ matrixMult แบบแรก จะไดคําสั่งที่บรรทัดที่ 10 เปนคําสัง่ มาตรเวลา (บรรทัดที่ 9 ก็ใช ไดเหมือนกัน) เพราะเปนบรรทัดทีถ่ กู เรียกใชมากกวาบรรทัดอืน่ ๆ บรรทัดที่ 10 นี้อยูภายในวงวนสามวงซอน กันซึง่ แตละวงหมุนเปนจํานวน n รอบ จึงถูกเรียกใชเปนจํานวน

n

n

n

¦¦¦1 [ n 3 ครัง้ ตีความไดวา i [1 j [1 k [1

3

n ขอใหสังเกตตรงนี้วาเราไมสนใจคําสั่งที่บรรทัดที่ 4 ถึง 6 เลย ทีเ่ ปนเชนนีเ้ พราะวาคําสัง่ ทีบ่ รรทัดที่ 6 อยูภายในวงวนสองวงซอนกันซึ่งเพิ่มคาตั้งแต 1 ถึง n ซึ่งหมุน เปนจํานวน n2 ครัง้ ทีน่ อ ยกวาคําสัง่ มาตรเวลาทีเ่ ราเลือก matrixMult ใชเวลาการทํางานเปนฟงกชันแบบ

กิจกรรม 2.2 พิจารณาคําสั่งมาตรเวลา ขอใหนกั ศึกษาพิจารณาดูวา คําสัง่ ใดควรเปนคําสัง่ มาตรเวลาสําหรับ พบวาเมื่อนับแลวจะไดผลเชนเดียวกัน เรื่องที่ 2.2.4

matrixMult

แบบทีส่ อง จะ

การวิเคราะหเชิงเสนกํากับ

เนื่องจากเราใชจํานวนครั้งที่คําสั่งตางๆ ในโปรแกรมที่ถูกใชงาน (หรือจะพิจารณาเฉพาะคําสั่งมาตร เวลาก็ได) เปนตัวสะทอนถึงเวลาการทํางาน การนําผลการวิเคราะหของหลายๆ โปรแกรมมาเปรียบเทียบกัน เปนสิง่ ทีต่ อ งระวังเปนพิเศษ เพราะคําสั่งแตละคําสั่งของโปรแกรมตางๆ อาจใชเวลาการทํางานจริงซึ่งตางกัน แตเราจะมีความมั่นใจสูงมากในการเปรียบเทียบผล ถาเราเลือกใชการเปรียบเทียบเมื่อขอมูลมีจํานวนมาก (ซึ่งหมายถึงคาของตัวแปร n ที่ใชในตัวอยางที่ผานมามีคาสูง) เรียกวาการศึกษาพฤติกรรมของเวลาการ ทํางานของโปรแกรมเชิงเสนกํากับ นัน่ คือศึกษาการเติบโตของเวลาการทํางานเมือ่ n มีคามาก มีคามากแบบ เขาใกลอนันตไปเลย ตัวอยางเชนถาตองการเปรียบเทียบฟงกชัน 1000n กับ 0.1n2 ก็ลองวาดกราฟเสนของ ทั้งสองฟงกชันดูจะไดดังภาพประกอบ 2.1 จะเห็นไดวา 1000n ใหคามากกวา 0.1n2 เมื่อ n ℑ 10000 แตเมื่อ n มีคาเกิน 10000 ฟงกชัน 0.1n2 จะใหคามากกวาเสมอ ทัง้ นีเ้ พราะ n2 มีอัตราการเติบโตที่เร็วกวา n มาก 5.E+07

1000n 0.1n^2

4.E+07

3.E+07

2.E+07

1.E+07

0.E+00 0

5000

10000

15000

20000

25000


36 ภาพประกอบ 2.1 กราฟเสนของฟงกชัน 1000n กับ 0.1n2 หรือจะใชเรื่องของลิมิตเพื่อเปรียบเทียบการเติบโตของฟงกชันโดยไมตองวาดกราฟเสน ก็จะไดวา § 1000n · ¸ ν lim §¨ 10000 ·¸ ν 0 lim ¨ n⇓√© n ¹

n⇓√¨© 0.1n 2 ¸¹

แสดงใหเห็นวาเมื่อ n มีคามากเปนอนันต สัดสวนของ 1000n กับ 0.1n2 มีคาเขาใกลศูนย หมายความ 0.1n2 นั้นใหคาที่เพิ่มขึ้นเมื่อ n เพิ่มมากกวาคาของ 1000n มาก จึงมีอัตราการเติบโตที่เร็วกวา ภาพประกอบ 2.2 แสดงตัวอยางฟงกชันที่มักพบบอยๆ ซึ่งมีอัตราการเติบโตแตกตางกัน

2n

n2

n log n

n ภาพประกอบ 2.2 ตัวอยางฟงกชันที่มีอัตราการเติบโตแตกตางกัน ดังนั้นเมื่อตองการเปรียบเทียบการเติบโตของฟงกชัน f(n) กับ g(n) (ตองขอเนนวาในทีน่ เ้ี ราสนใจ เฉพาะ n และฟงกชันของ n ที่ใหคาไมติดลบ เพราะฟงกชันนี้แทนเวลาการทํางานของโปรแกรม) ก็เพียงแต หาคาลิมิตของ f(n) / g(n) เมื่อ n ⊂℘ ซึ่งสามารถตีความผลที่ไดดังนี้ ถา ถา ถา

f ( n) [0 n⊂℘ g ( n) lim

lim

f ( n)

n⊂℘ g ( n)

[℘

f ( n) [c n⊂℘ g ( n) lim

แสดงวา f(n) โตชากวา g(n) แสดงวา f(n) โตเร็วกวา g(n) โดยที่ c ⋅ 0 และ c ⋅ ℘ แสดงวา f(n) โตในอัตราที่เทากับ g(n)

เมื่อมีการใชลิมิต ก็ขอใหนึกถึงกฎของโลปตาล (l'Hôpital's Rule) ที่เคยเรียนกันในวิชาแคลคูลัส จะชวยหาคํา ตอบจัดการไดงายขึ้น ขอเขียนทบทวนใหดูโดยไมพิสูจนที่มาดังนี้ กฎของโลปตาล ถา f(n) และ g(n) เปนฟงกชนั ทีห่ าอนุพนั ธได โดยที่ lim f (n) ∴ ⊗ และ n ⊆⊗

f (n ) f ℑ(n ) lim g ( n ) ∴ ⊗ แลว lim ∴ lim n ⊆⊗ n ⊆⊗ g ( n ) n ⊆ ⊗ g ℑ( n )

ตัวอยาง 2.1 จงเปรียบเทียบอัตราการเติบโตของ 100n2 + 5n + 1 กับ n2 ใชกฎของโลปตาลไดวา สองโตเร็วเทากัน

lim

n⊆⊗

100n 2 ϑ 5n ϑ 1 n2

200n ϑ 5 200 ∴ lim ∴ 100 n 2 n⊆⊗ n⊆⊗ 2

∴ lim

แสดงวาฟงกชันทั้ง


37 ตัวอยาง 2.2 จงเปรียบเทียบอัตราการเติบโตของ ln9 n กับ n0.1 ใชกฎของโลปตาลไดดังนี้ lim

ln 9 n

n ⊆⊗ n 0.1

∴ lim

n ⊆⊗

∴ lim

(9 ln 8 n )(1 / n ) 0.1n (0.1Λ1)

∴ lim

9 ln 8 n

n⊆⊗ 0.1n 0.1

7

9  8 ln n

n ⊆⊗ ( 0.1) 2 n 0.1

... ∴ lim

9  8 1 ln 0 n

n ⊆⊗ ( 0.1) 9 n 0.1

สรุปไดวา ln9 n โตชากวา n0.1

∴0

อยากจะขอเนนย้ําตรงนี้เลยวาถา f1(n) และ f2(n) เปนฟงกชันของเวลาการทํางานของโปรแกรมที่ 1 และโปรแกรมที่ 2 ตามลําดับ โดยที่ n ขนาดของขอมูลของปญหาที่โปรแกรมทั้งสองรับเขาไปประมวลผล และถา f1(n) เปนฟงกชันที่โตเร็วกวา f2(n) ยอมสรุปไดวาโปรแกรมที่ 1 ทํางานชากวาโปรแกรมที่ 2 เมื่อ n มี คามาก ขอใหนักศึกษาอานขอความนี้ใหมอีกครั้ง สังเกตตรงทีข่ ดี เสนใตอกี ครัง้ เพือ่ กันความสับสน และใน ทางกลับกัน เมื่อ f1(n) เปนฟงกชันที่โตชากวา f2(n) ยอมสรุปไดวาโปรแกรมที่ 1 ทํางานเร็วกวาโปรแกรมที่ 2 เมื่อ n มีคามาก เรื่องที่ 2.2.5 สัญกรณโอใหญ การบรรยายเวลาการทํางานของโปรแกรมดวยฟงกชันซึ่งวิเคราะหมาไดจากการนับคําสั่งมาตรเวลา ตามทีไ่ ดนาํ เสนอมานัน้ บางทีอาจไดผลทีด่ ลู มุ ลาม เชน f(n) = 10n2 + n log n + 27n + 4 เปนตน เรา สามารถแทนตัวฟงกชันที่แลดูยุงๆ ยาวๆ ใหกระทัดรัดมากขึ้นไดดวยการใชสัญกรณโอใหญ (Big O notation) โดยเราเขียน f(n) = O(g(n)) เมื่อ f(n) เปนฟงกชันที่โตไมเร็วกวา g(n) เชิงเสนกํากับ นัน่ คือ f(n) = O(g(n)) เมื่อ

f ( n) [ c โดยที่ g n⊂℘ ( n) lim

c ∇ 0 และ c ⋅ ℘

เชน 10n2 + n log n + 27n + 4 = O(n2) ตีความงายๆ วา 10n2 + n log n + 27n + 4 เปนฟงกชันที่ โตไมเร็วกวา n2 เชิงเสนกํากับ ซึ่งใหความรูสึกกับผูอานไดทันทีวาโปรแกรมที่ใชเวลาการทํางานแบบ O(n2) มี อัตราการเติบโตของเวลาการทํางานไมเลวไปกวาแบบ n2 เมื่อ n มีคามาก ดังนัน้ การเปรียบเทียบประสิทธิ ภาพเชิงเวลาระหวางโปรแกรมตางๆ จึงกระทําไดงายขึ้น เราสามารถใหนิยามกับสัญกรณโอใหญไดในอีกรูปแบบหนึ่ง โดยกําหนดให O(g(n)) คือเซตของ ฟงกชันตางๆ ที่โตไมเร็วกวา g(n) เขียนไดดงั นี้ µ(g(n)) = { f(n) |

มีคาคงตัวบวกสองตัวคือ c และ n0 ที่ทําให f(n) ℑ cg(n) เมื่อ n ∇ n0 }

หมายความวาถา f(n)  µ(g(n)) แสดงวาการเติบโตของ f(n) จะถูกกําหนดขอบเขตดานบนไวดวย ลักษณะการเติบโตของ g(n) นั่นคือเราสามารถหาคาคงตัวบวก c ที่ f(n) ℑ cg(n) เมื่อ n ∇ n0 แสดงเปนตัว อยางไดดงั ภาพประกอบ 2.3


38 c g(n) f (n)

n0

n

ภาพประกอบ 2.3 f(n)  µ(g(n)) ตัวอยาง 2.1 จงแสดงใหเห็นจริงวา 2n2 + 500n + 1000log n = O(n2) ตองหาคา c และ n0 ที่ทําให 2n2 + 500n + 1000log n ℑ cn2 เปนจริงเสมอเมือ่ n ∇ n0 กําหนด ให c = 2+500+1000 = 1502 ก็สบายใจไดเลยวาอสมการนี้เปนจริงแนเมื่อ n ∇ 1 ตัวอยาง 2.2 จงแสดงใหเห็นจริงวา loga n = O( logb n ) สําหรับคาคงตัว a, b > 1 เนือ่ งจากเราสามารถแปลงฐานของ log จากฐาน a ไปเปนฐาน b ไดดวยการหารดวยคาคงตัว logb a นัน่ คือ loga n = (logb n) / (logb a) ดังนัน้ สรุปไดวา loga n = O( logb n ) ตัวอยางนี้ชี้ให เห็นวาเรามักจะไมใสฐานของ log ในสัญกรณเชิงเสนกํากับ เชน O(log n) เพราะวานอกจากจะ สะดวกแลว ยังไมมีผลใดๆ ดวย ดังนัน้ ในเชิงเสนกํากับแลว log1.1 n กับ log100 n มีอตั ราการเติบ โตเทากัน ตัวอยาง 2.3 :

จงแสดงใหเห็นจริงวา log n! = O( n log n )

จากนิยาม n! = n⌡ (n–1) … 2⌡1 แทนทุกๆ พจนทางขวาดวย n จะไดวา n! ℑ nn หาคา log ทั้ง สองขางได log n! ℑ n log n = µ(n log n) ตัวอยาง 2.4 :

n

จงแสดงใหเห็นจริงวา ¦ i k i [1

Φ Γ โดยที่ k เปนคาคงตัว

[ O n k Ι1

เนื่องจากภายในผลบวกนั้น i มีคาตั้งแต 1 ถึง n แสดงวา i ℑ n สรุปไดวา ik ℑ nk ดังนัน้ เมือ่ รวม ทุกๆ ik ตั้งแต 1 ถึง n ยอมไดวา ¦in[1 i k ℑ ¦in[1 n k = nk+1 = O(nk+1) การใชสัญกรณโอใหญเพื่อแทนประสิทธิภาพเวลาการทํางานนั้น มีประเด็นที่ตองเขาใจดังนี้ 1. หลายคนอาจถามตอนนี้แลววาทําไมบางทีเขียน f(n) = µ(g(n)) บางทีก็เขียน f(n)  µ(g(n)) แลวจะตองใช = หรือ  กันแน ? แบบที่ถูกตองใช  เพราะวาตามนิยามแลว O(g(n)) นัน้ เปน เซต แตเรากลับพบกันบอยมากๆ เลยวาเขาใชเครือ่ งหมาย = กัน เพราะวาสะดวกดี อีกทัง้ อาน


39 ไดราบรืน่ โดยทั่วไปเราอาน f(n) = µ(g(n)) วา "f(n) เปนโอใหญของ g(n)" จึงตองคํานึงไวเสมอ วาเปน = ทางเดียว หมายความวา f(n) = O(g(n)) ไมไดหมายความวา O(g(n)) = f(n) 2. โดยทั่วไปแลวเราจะใชโอใหญเพื่อแทนฟงกชันที่ซับซอนดวยฟงกชันที่แลดูงายๆ เชนเขียน 10n2 + n log n + 27n + 4 = O(n2) สวน 10n2 = O(25n2 + n log n + 93n + 5) ถึงแมจะถูก ตองตามนิยาม แตก็จะไมเขียนกัน เพราะจุดประสงคของการใชสัญกรณโอใหญก็เพื่อแทนสิ่งที่ ยุง ดวยสิ่งที่เขาใจงายกวา 3. จากตัวอยาง 10n2 + n log n + 27n + 4 = O(n2) จะพบวา 10n2 + n log n + 27n + 4 ก็เปน O(n3) เปน O(n90) หรือเปน O(2n) ดวยเชนกัน เพราะ n3, n90 และ 2n ลวนแลวแตเปนฟงกชันที่ โตเร็วกวา n2 เชิงเสนกํากับทัง้ สิน้ แตเรามักเลือกใช g(n) ที่โตชาๆ ชาสุดเทาที่จะชาไดในการ แทน f(n) ดวย O(g(n)) ลองคิดก็แลวกันวาสมมติวาโปรแกรม A เรียกใชคําสั่งมาตรเวลาเปน จํานวน 10n2 + n log n + 27n + 4 ก็คงไมมีเหตุผลที่จะโฆษณาใหคนในวงการทราบวา A ใช เวลาการทํางานเปน O( n90 ) ถึงแมจะไมผิดที่จะบอกวา A ใชเวลาการทํางานไมเลวกวา n90 เชิง เสนกํากับ แตก็นาจะอวดวา A ใชเวลาการทํางานไมเลวกวา n2 เชิงเสนกํากับ จะดีกวา 4. เราใช O(1) แทนเซตของฟงกชันที่ไมโต ซึ่งรวมถึงคาคงตัวทั้งหลายดวย นอกจากวิธีการใชลิมิตและการใชนิยามของขอบเขตบนมาชวยเขียนบรรยายฟงกชันที่ยุงดวย ฟงกชันที่งายในโอใหญแลว มีอีกวิธีหนึ่งที่มักใชไดผลอยางรวดเร็ว ก็คือการตัดพจนที่โตชากวา และการตัด สัมประสิทธิท์ เ่ี ปนคาคงตัวออก เชน f(n) = 10n2 + n log n + 27n + 4 พบวาประกอบดวยพจนยอยๆ ที่เมื่อ เรียงลําดับตามอัตราการเติบโตจากมากไปนอยจะไดลําดับดังนี้คือ 10n2, n log n, 27n, 4 (อยาลืมวา n โตเร็ว กวา log n ดังนัน้ n2 ก็ยอ มโตเร็วกวา n log n) ดังนัน้ ก็เลือกสนใจเฉพาะพจนทโ่ี ตเร็วสุด เพราะในการ วิเคราะหเชิงเสนกํากับพจนที่โตเร็วสุดจะเปนตัวที่มีอิทธิพลสูงสุดในการกําหนดคาของฟงกชัน เมื่อ n มีคา มาก จึงสามารถเขียนไดเลยวา 10n2 + n log n + 27n + 4 = O(10n2) และเมื่อมาดูที่พจน 10n2 จะพบวา สัมประสิทธิซ์ ง่ึ เปนคาคงตัว 10 นัน้ สามารถตัดทิง้ ได เพราะไมมีผลใดๆตออัตราการเติบโต (คาลิมิตของ f(n) / g(n) จะไมเปลี่ยนแปลงเลยไมวาจะมี 10 อยูห รือไม) ดังนั้นจะไดวา 10n2 + n log n + 27n + 4 = O(n2) เรื่องที่ 2.2.6

ตัวอยางการวิเคราะหโปรแกรมเชิงเสนกํากับ

ตัวอยาง 2.5 :

จงวิเคราะหเวลาการทํางานเชิงเสนกํากับของสวนของโปรแกรมขางลางนี้ for i:=1 to 100 do for j:=1 to i do s := s + 1;

01: 02: 03:

ในที่นี้บรรทัดที่ 3 เปนคําสัง่ มาตรเวลา ซึ่งถูกเรียกใชงานเปนจํานวน 100 i

100

¦¦ ¦ i [ i [1 j [1

1[

i [1

100(100 Ι 1) [ 5050 2

ครัง้ หมายความวาใชเวลาคงตัวไมขึ้นกับขนาดของขอ

มูลขาเขาแตอยางใด ดังนั้นสวนของโปรแกรมนี้ใชเวลาเปน O(1)


40 ตัวอยาง 2.6 :

จงวิเคราะหเวลาการทํางานเชิงเสนกํากับของสวนของโปรแกรมขางลางนี้ 01: 02: 03:

for i:=1 to n do for j:=1 to i do s := s + 1;

ในที่นี้บรรทัดที่ 3 เปนคําสัง่ มาตรเวลา จะพบวาถูกเรียกใชงานเปนจํานวน n

i

n

¦¦1 [ ¦ i [ i [1 j [1

ตัวอยาง 2.7 :

i [1

n(n Ι 1) n 2 n [ Ι 2 2 2

ครัง้ ดังนั้นจึงใชเวลาเปน O(n2)

จงวิเคราะหเวลาการทํางานเชิงเสนกํากับของสวนของโปรแกรมขางลางนี้ 01: 02:

while n > 0 do n := n div 2;

ในที่นี้บรรทัดที่ 3 เปนคําสัง่ มาตรเวลา ใหสังเกตวาวงวนนี้จะเลิกทํางานเมื่อ n ℑ 0 ก็ตองมาดูวา คาของ n เปลีย่ นแปลงอยางไร คาของ n นัน้ ลดลงทีละครึง่ (ปดเศษทิ้ง) ก็แสดงวา n จะตองจบ ลงที่ศูนยอยางแนนอน (ในที่นี้ถือวา n มีคาเริ่มดวยจํานวนไมติดลบ) การทีม่ คี า ลดลงทีละครึง่ นัน้ n ในรอบที่ k ยอมมีคา n / 2k โดยกอนที่ n จะมีคา เปนศูนยแลวเลิกทํางานนัน้ n ก็ตอ งเทากับ 1 ดังนั้นรอบที่ทําให n มีคาเปน 1 ก็คอื k = log2 n สรุปไดวาวงวน while หมุนเปนจํานวน 1+log2 n รอบ ดังนัน้ เวลาการทํางานเปน O( log2 n ) ตัวอยาง 2.8 :

จงวิเคราะหเวลาการทํางานเชิงเสนกํากับของสวนของโปรแกรมขางลางนี้ 01: 02: 03: 04: 05: 06:

i := 1; j := n; while i < j do begin i := i + 3; j := j – 5; end;

วงวน while ทํางานตราบเทาที่ i < j โดยที่ i มีคาเริ่มตนที่นอยกวา j คาของ i เพิม่ ทีละสาม ในช ณะทีค่ า j ลดลงทีละหา แสดงวาจะตองมีชวงที่ i ∇ j แลวหลุดจากวงวนแน และคาของ i และ j จะเขยิบเขาหากันทีละ 8 แสดงวา จํานวนรอบที่หมุนในวงวนมีคาอยางมาก n/8 รอบ ดังนัน้ เวลา การทํางานเปน O( n ) โดยสรุปหาก n มาก มาตรวัดประสิทธิภาพสําหรับสัญกรณโอใหญ จากมากไปนอย ดังแสดงในตา รางที่ ตาราง 2.1


41 ตาราง 2.1 มาตรวัดประสิทธิภาพสําหรับสัญกรณโอใหญ จากมากไปนอย n=8

n =128

n = 1024

O(1)

1

1

1

O(log2n)

3

7

10

O(n)

3

11

32

O(n)

8

128

1,024

O(n⌡log2n)

24

896

10,240

O(n2)

64

16,192

1,048,576

O(n3)

512

2,097,152

1,073,741,824

O(2n)

256

3.40 x 1038

1.79 x 10308


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.