วันศุกร์ที่ 4 มีนาคม พ.ศ. 2559

บทที่ 2 : การประเมินผลโปรแกรมที่เขียน

การประเมินผลโปรแกรมที่เขียน

การเขียนโปรแกรมใดๆ ต้องพิจารณาถึงข้อจำกัดที่สำคัญของคอมพิวเตอร์ ดังนี้

     - โปรแกรมที่เขียนนั้นใช้เนื้อที่ความจำมากน้อยแค่ไหน
     - โปรแกรมนั้นมีอัลกอริทึ่มที่เร็วเพียงใด

เนื่องจากเป็นข้อจำกัดทางคอมพิวเตอร์ ดังนั้น จุดประสงค์หลักของการเขียนโปรแกรมที่ดี จึงมีเป้าหมายอยู่ที่ การได้โปรแกรมที่ทำงานได้เร็วที่สุดภายใต้การใช้เนื้อที่ความจำที่น้อยที่สุด กล่าวคือการใช้ทรัพยากรอย่างคุ้มค่านั่นเอง


กระบวนการวัด ที่นิยม มี 2 แบบ
     - การวิเคราะห์เวลาที่ใช้ในการประมวลผล (Time Complexity Analysis)
     - การวิเคราะห์หน่วยความจำที่ใช้ในการประมวลผล (Space Complexity Analysis)

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

การวิเคราะห์เวลาที่ใช้ในการประมวลผล (Time Complexity Analysis)
      การประเมินผลความเร็วของโปรแกรม หรือ อัลกอริทึ่ม สามารถประเมินได้ในรูปแบบของฟังก์ชั่น ที่เรียกกันว่า Big-O notation

** จริงๆ รายละเอียดมีเยอะกว่านั้น แต่ในที่นี้จะขอกล่าวถึงแค่ Big-O notation 

Big-O notation
     - ใช้ในการระบุทรัพยากรที่ใช้ในการทำงานของอัลกอรึทึ่ม เมื่อขนาดของข้อมูลรับเข้า (Input) เปลี่ยน        ไป ซึ่งความหมายของทรัพยากรในที่นี้ จะหมายถึง เวลา กล่าวคือ เราจะสนใจความสัมพันธ์ระหว่าง        เวลา กับ ขนาดของ Input หรือ อาจกล่าวได้อีกทางหนึ่งว่า หาก Input ที่มีขนาดใดขนาดหนึ่ง      
       (Input ข้อมูลรับเข้า ขนาด N) จะใช้เวลาในการทำงานมากที่สุด (Upper bound) เป็นเท่าไหร่ ซึ่ง
       Big-O เป็นฟังก์ชันที่นิยมใช้มากที่สุดในการประเมินผลของอัลกอริทึ่ม

ความเร็วในการทำงานของแต่ละอัลกอริทึ่มที่พบได้บ่อย โดยเรียงจากเร็วไปช้า มีดังนี้

     1. ความเร็วในการประมวลผลแบบฟังก์ชั่น ลอการิทึ่มมิก (Logarithmic)
       O(log n)

     2. ความเร็วในการประมวลผลแบบฟังก์ชั่น เส้นตรง (Linear)
       O(n)

     3. ความเร็วในการประมวลผลแบบ
       O(n log n)
   
     4. ความเร็วในการประมวลผลแบบฟังก์ชั่นกำลังสอง (Quadratic)
       O(n^2)

     5. ความเร็วในการประมวลผลแบบฟังก์ชั่นกำลังสาม (Cubic)
       O(n^3)

     6. ความเร็วในการประมวลผลแบบฟังก์ชั่นเอ็กซ์โปเนนเชียล (Exponential)
       O(2^n)

การพิจารณาว่ามี Big-O แบบใดนั้น จะพิจารณาที่ฟังก์ชั่น f(n) ซึ่งเป็นแต่ละเทอมในการทำงาน

ตัวอย่าง

for (i=0; i<n; i++){
     for (j=0; i<n; j++){
            คำสั่ง A
     }
}

จากตัวอย่าง เมื่อพิจารณาจะพบว่า คำสั่ง A จะถูกปฏิบัติ (Execute) ภายใต้ ลูป (Loop) i ที่ ถูกปฏิบัติ n ครั้ง และ ลูป j ที่ถูกปฏิบัติอีกจำนวณ n ครั้ง ดังนั้นคำสั่ง A จะถูกปฏิบัติภายใต้ เทอมการทำงาน n*n ครั้ง มี Big-O ที่มากที่สุดคือ O(n^2)


โดยเฉพาะเทอมที่ทำให้เกิด คอสท์ (Cost) สูงสุดในการทำงาน เช่น การทำซ้ำ หรือ ลูป (Loop)
ซึ่งมีหลายแบบ ดังนี้

1. ลูปเชิงเส้น (Linear Loop) 
ตัวอย่าง

for (i=0; i<n; i++)           -----> f(n) = n

for (i=0; i<n; i+=2)         -----> f(n) = n/2
========================================================================
2. ลูปแบบลอการิทึ่มมิก (Logarithmic Loop)
ตัวอย่าง

for (i=0; i<; i*=2)           ------> f(n) = log n

for (i=0; i<n; i/=2)          ------> f(n) = log2n
========================================================================
3. ลูปแบบซ้อน (Nested Loop) 

แบ่งเป็น

3.1 ลูปแบบซ้อนชนิดลอการิทึ่มเชิงเส้น (Linear Logarithmic Loop)
ตัวอย่าง

for (i=0; i<n; i++){         ------>f(n) = n
    for(j=0; j<n; j*=2){    ------>f(n) log n
   คำสั่ง A
   }
}

ดังนั้น f(n) = n log n
--------------------------------------------------------------------------------------------------------------------------
3.2 ลูปแบบซ้อนชนิดกำลังสอง (Quadratic Loop)
ตัวอย่าง

for (i=0; i<n; i++){        ------>f(n) = n
     for (j=0; j<n; j++){   ------>f(n) = n
     คำสั่ง A
     }
}

ดังนั้น f(n) = n^2
--------------------------------------------------------------------------------------------------------------------------
3.3 ลูปแบบซ้อนกำลังสองชนิดขึ้นต่อกัน (Dependent Quadratic)
ตัวอย่าง

for (i=0; i<n; i++){        ------>f(n) = n
     for (j=0; j<i; j++){    ------>f(n) = n
     คำสั่ง A
     }
}

ดังนั้น f(n) = n((n+1)/2)


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

การวิเคราะห์หน่วยความจำที่ใช้ในการประมวลผล (Space Complexity Analysis)

     การวิเคราะห์หน่วยความจำทั้งหมดที่โปรแกรมใช้ในการประมวลนั้น เพื่อให้ทราบถึงขนาดข้อมูลที่สามารถป้อน หรือ ส่ง เข้ามาให้อัลกอริทึ่มประมวลผลแล้วไม่เกิดข้อผิดพลาด หรือเพื่อให้ทราบถึงขนาดหน่วยความจำของเครื่องคอมพิวเตอร์ว่ามีเพียงพอสำหรับการเก็บข้อมูลทั้งหมดในขณะทำการประมวลผลหรือไม่ มีประโยชน์อย่างมากเมื่อทำงานกำกับหน่วยความจำที่จำกัด เช่น การประมวลผลผ่านเครือข่าย การทำงานของโปรแกรมบนเครื่องมือถือที่มีทรัพยากรจำกัด เป็นต้น


องค์ประกอบในการวิเคราะห์แบ่งออกเป็น 3 ส่วน ดังนี้

1. Instruction Space
      คือ ขนาดของหน่วยความจำที่จำเป็นต้องใช้ในขณะที่ คอมไพเลอร์ (Compiler) ทำการ คอมไพล์ (compile) โปรแกรม

2. Data Space
     คือ ขนาดหน่วยความจำที่จำเป็นต้องใช้สำหรับเก็บข้อมูลค่าคงที่ และตัวแปรที่ใช้ขณะประมวลผลโปรแกรม แบ่งออกเป็น 2 ประเภท

     2.1 Static memory ตัวอย่าง เช่น การประกาศขนาดของอาเรย์เพื่อจองพื้นที่หน่วยความจำ

     2.2 Dynamic memory ตัวอย่าง เช่น พ้อยเตอร์ (Pointer) ในภาษา C หรือ ลิ้งค์ลิสต์ (Link list) ที่
           สามารถเพิ่มหรือลดขนาดการเก็บข้อมูลได้แบบอัตโนมัติ โดยไม่ต้องประกาศจองพื้นที่หน่วย  
    ความจำ

3. Environment Stack Space 
     คือ หน่วยความจำที่ใช้สำหรับเก็บข้อมูลผลลัพท์ที่ได้จากการประมวลผล เพื่อรอเวลาที่จะนำกลับมาใช้ใหม่ในโปรแกรม ซึ่งหน่วยความจำประเภทนี้จะเกิดขึ้นเมื่อมีการใช้งานโปรแกรมเท่านั้น

ตัวอย่าง การวิเคราะห์หน่วยความจำที่ใช้ในการประมวลผล

int result
     result = data1 + data2

 จากตัวอย่าง มีการประกาศตัวแปรทั้งหมด 3 ตัวแปร
     - result
     - data1
     - data2

     ทั้งหมดถูกกำหนด ชนิด (Type) ให้ เป็น int (ตัวเลข Integer : int) ซึ่ง ชนิด ของข้อมูลจะใช้หน่วยความจำเท่าไหร่ขึ้นอยู่กับภาษาที่เขียน เช่น ภาษา C ใช้พื้นที่หน่วยความจำ 2 ไบต์ ภาษาจาวา ใช้พื้นที่หน่วยความจำ 4 ไบต์ ดังนั้น จากตัวอย่างนี้ มีตัวแปรทั้งหมด 3 ตัว ถ้าเป็น ภาษา C จะใช้หน่วยความจำ 3*2 = 6 ไบต์ และ ภาษาจาวา จะใช้หน่วยความจำ 3*4 = 12 ไบต์

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

อ้างอิง
1) บล็อกของอาจารย์ที่เคารพ thaiall :D

2) Scheguc News

3) หนังสือ : คู่มือเรียนโครงสร้างข้อมูล และ อัลกอริทึ่ม (Data Structure & Algorithm)

4) หนังสือโครงสร้างข้อมูลเพื่อการออกแบบโปรแกรมคอมพิวเตอร์




วันอาทิตย์ที่ 28 กุมภาพันธ์ พ.ศ. 2559

บทที่ 1 : โปรแกรมแบบมีโครงสร้าง


โปรแกรมแบบมีโครงสร้าง (Structured programming)

การเขียนโปรแกรมคอมพิวเตอร์ที่ดีนั้น ควรออกแบบโปรแกรมในลักษณะที่มีโครงสร้างและลำดับขั้นตอนการทำงานที่แน่นอน ซึ่งโปรแกรมแบบมีโครงสร้างที่ดีนั้นจะมีโครงสร้างที่ง่ายต่อการทำความเข้าใจ และรวมไปถึงง่ายต่อการปรับปรุงแก้ไขในภายหลังด้วย ซึ่งการเขียนโปรแกรมแบบมีโครงสร้างสามารถใช้เครื่องมือในการอธิบายโครงสร้างได้ เช่น ผังงาน (Flowchart) และ โค้ดเทียม (Pseudo code) เป็นต้น และการแบ่ง โครงสร้างโดยทั่วไป มี 3 แบบ หลักๆ ดังนี้

1) โครงสร้างแบบลำดับ (Sequential structure)

คือ โครงสร้างที่ทำงานเป็นขั้นตอนเพื่อแก้ไขปัญหา และทำงานตามคำสั่งที่เขียนไว้แบบตามลำดับ ตั้งแต่คำสั่งแรกไปจนถึงคำสั่งสุดท้าย ดังแสดงในรูปที่ 1

2) โครงสร้างแบบทางเลือก (Selection or Decision structure)

คือ โครงสร้างการทำงานที่ที่มีเงื่อนไขการตัดสินใจ ซึ่งจะแบ่งเป็น

- การตัดสินใจ แบบ if....then....
          ซึ่ง ในส่วนของการตัดสินใจ จะมีทางเลือก 2 ทาง คือ จริง / เท็จ เสมอ ดังแสดงในรูปที่ 2

- การตัดสินใจ แบบ case
          เป็นกรณีที่ ในส่วนตัดสินใจ มีทางเลือกมากกว่า 2 ทางเลือก ดังแสดงในรูปที่ 3

3) โครงสร้างแบบวนซ้ำ (Repetition or Loop structure)
คือ โครงสร้างที่มีขั้นตอนการประมวลผลมากกว่า 1 ครั้ง โดยจำนวนครั้งการประมวลผลขึ้นอยู่กับเงื่อนไขการตัดสินใจการทำซ้ำ โดยแบ่งเป็น 2 ลักษณะการทำซ้ำ ดังนี้          

- การทำซ้ำแบบ do while
       
          มีการตรวจสอบเงื่อนไขการทำซ้ำทุกครั้งก่อนดำเนินการกิจกรรมใดๆ โดยถ้าเงื่อนไขเป็นจริงก็จะทำงานซ้ำไปเรื่อยๆ และจะหยุดเมื่อเงื่อนไขเป็นเท็จ ดังแสดงในรูปที่ 4


- การทำซ้ำแบบ do until
          ทำกิจกรรมเสร็จแต่ละครั้งก็จะมีการตรวจสอบเงื่อนไข โดยจะทำซ้ำไปเรื่อยๆ จนกระทั่งเงื่อนไขเป็นจริงแล้วจึงหยุดการทำงาน ดังแสดงในรูปที่ 5



========================================================================
ผังงาน (Flowchart)
คือ การใช้รูปภาพ หรือ สัญลักษณ์ อธิบายขั้นตอนการทำงาน

ตัวอย่าง สัญลักษณ์สำคัญในผังงาน

สัญลักษณ์ของ การเริ่มต้น และ จบ ผังงาน (Start หรือ End)
สัญลักษณ์ของ การกระทำ (Process) ถูกใช้เพื่อแสดงงานที่การกระทำในผังงาน
สัญลักษณ์ของ ส่วนการนำข้อมูลเข้า และ แสดงผลข้อมูล (Input / Output)
สัญลักษณ์ของ การตัดสินใจ (Decision)
เพื่อพิจารณาเงื่อนไข ระหว่าง จริง (True) และ เท็จ (False)
สัญลักษณ์ของ คำอธิบายประกอบ (Annotation)
ใช้เพื่อเขียนคอมเม้นต์ให้กับ ผังงาน
สัญลักษณ์ของ จุดเชื่อมต่อ (Connector)
ใช้รวมเส้นการทำงานให้ออกไปเหลือเพียงเส้นเดียว
สัญลักษณ์ของ ทิศทางการทำงาน (Direction Flow)
ใช้แสดงการไหลการงาน
========================================================================
โค้ดเทียม (Pseudo code)
คือ การแสดงขั้นตอน หรือ การอธิบายกระบวนการทำงาน โดยใช้ภาษาลดรูปที่เข้าใจง่าย
หลักการเขียน โค้ดเทียม โดยทั่วไป
     - ใช้คำที่เข้าใจง่าย
     - ใน 1 บรรทัด ควรมีเพียง 1 ประโยคโค้ดเทียม
     - ใช้ย่อหน้าเพื่อความเป็นระเบียบ
     - รูปแบบการทำงานของโค้ดควรเป็นแบบจากบนลงล่าง (Top to Down) และมีทางออกทางเดียว
     - ควรมีรูปแบบคำสั่ง

========================================================================
Abstract Data Type หรือ ADT
คือ การประกาศคุณสมบัติของโครงสร้างข้อมูล และกลุ่มตัวดำเนินการที่กระทำกับโครงสร้างข้อมูล

ADT
เป็นกระบวนการที่พัฒนามาจากกระบวนการแก้ไขปัญหา แสดงถึงความสัมพันธ์ ระหว่างโครงสร้างข้อมูล และ กลุ่มตัวดำเนินการที่เป็นฟังก์ชัน โดยจะกำหนดการทำงานของโปรแกรมที่จะกระทำกับโครงสร้างข้อมูล ซึ่งแต่ละกลุ่มตัวดำเนินการจะทำงานอย่างอิสระไม่เกี่ยวเนื่องกัน โดยไม่มีการส่งค่าระหว่างกลุ่มตัวดำเนินการ และจะต้องมีลักษณะการทำงานที่ชัดเจน

ตัวอย่าง รายการ ADT

1. สนใจ วันที่ ก่อน วันที่กำหนด มาให้
2. สนใจว่าเป็นวันหยุด
3. สนใจจำนวนวันหยุด
4. สนใจว่าเป็น วันแรก ของ เดือน ที่กำหนดมาให้    
5. สนใจ วันที่ ถัดไป ของ วันที่ ที่กำหนด มาให้

จาก รายการ ADT ในข้างต้น สามารถนำมาเขียน ให้อยู่ในรูป Pseudo code ได้ ดังนี้

+dayBefore(in date1:Date, date2:Date):boolean
//คืนค่า boolean : true เมื่อ date1 เป็นวันที่มาก่อน  date2 นอกเหนือจากนั้นให้ คืนค่า boolean : false

+Holiday(in mount:Date):boolean
//คืนค่า boolean : true เมื่อ เป็นวันหยุด นอกเหนือจากนั้นให้ คืนค่า boolean : false

+countHolidays(in mount:interger):integer
//คืนค่า integer เป็นจำนวนวันหยุด

+firstDay(in Mount:integer):Date
//คืนค่า date เป็นวันแรกของเดือนที่กำหนด

+nextDay(in Date:aDate):Date
//คืนค่า date เป็นถัดไปจากวันที่กำหนดให้มา ในตัวแปร aDate

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ตัวอย่าง

+countHolidays(in mount:integer):integer
//คืนค่า integer เป็นจำนวนวันหยุด ของ เดือน ที่ให้มา

ซึ่งภายในฟังก์ชันมีกระบวนการ ดังนี้

date = กำหนดให้ เริ่มต้นที่วันแรกของ เดือน
hDate = 0 //กำหนดค่าให้เป็น 0 ในเบื้องต้น

if (date = วันหยุด) //if ที่ 1
{
hDate = hDate+1
date = วันถัดไป
}
else{
date = วันถัดไป
//end if ที่ 1


while (date != วันแรกของเดือน)
    {
          if (date = วันหยุด){ //if ที่ 2
          hDate = hDate+1
          } //end if ที่ 2

date = วันถัดไป

    }//end while

========================================================================

ขอบคุณข้อมูลอนุเคราะห์บางส่วน และภาพบางส่วน จาก

1)ผังงานโครงสร้าง (Structure Flowchart)

2)สัญลักษณ์ Flowchart ความหมายและวิธีใช้เขียนผังงาน

วันพฤหัสบดีที่ 18 กุมภาพันธ์ พ.ศ. 2559

บทที่ 0 : ว่าด้วยเรื่องโคตรจะพื้นฐานของโครงสร้างข้อมูลและอัลกอริทึ่ม!

โครงสร้างข้อมูล (Data Structure)

ภาษาชาวบ้าน คือ รูปแบบการจัดเก็บข้อมูลโดยมีการกำหนดคุณสมบัติต่างๆ เพื่อให้ง่ายต่อการจัดการข้อมูล อาทิ เช่น การเก็บหนังสือไว้ในตู้ของห้องสมุด ส่วนในทางคอมพิวเตอร์ คือ การจัดการข้อมูลในหน่วยความจำภายในของเครื่องคอมพิวเตอร์ ซึ่งจะมีรูปแบบการจัดเก็บ และข้อกำหนดคุณสมบัติพื้นฐานของข้อมูลเพื่อสร้างความสัมพันธ์ภายในกลุ่ม โดยตัวอย่างการจัดเก็บข้อมูลที่อยู่ในรูปแบบของโครงสร้างข้อมูล อาทิ เช่น Array, Link-list, Stack, Binary tree เป็นต้น

อัลกอริทึ่ม (Algorithm)

คือ กระบวนการ ขั้นตอน วิธีการทำงาน ที่ทำงานตามลำดับเป็นขั้นตอน เพื่อใช้ในการแก้ไขปัญหาอย่างใดอย่างหนึ่ง และเมื่อลองพิจารณาดูจากกิจวัตรประจำวัน ก็จะพบว่า อัลกอริทึ่ม เป็นสิ่งที่พบเจอได้ง่ายโดยที่เรามักไม่ทันได้สังเกต อาทิ เช่น ขั้นตอนการทำไข่เจียว และ การจัดเรียงข้อมูลในแฟ้มเอกสารอย่างไรเพื่อให้ง่ายต่อการค้นหาข้อมูลในแฟ้ม เป็นต้น




*********************************************************************************
พอมาถึงตรงนี้...ไม่มีอะไรมากแค่อยากจะบอกว่า...
ในการทำงานของคอมพิวเตอร์นั้น โครงสร้างข้อมูล และ อัลกอริทึ่ม เป็นสิ่งที่สำคัญมาก!
เนื่องจากเป็นปัจจัยหลักในการกำหนดการใช้ทรัพยากรภายในที่มีอยู่จำกัดของเครื่อง...
อาทิ เช่น หน่วยความจำ เป็นต้น

ดังนั้นการจัดการบริหารโครงสร้างข้อมูล และ อัลกอริทึม ที่ดี จึงมีประโยชน์มาก เพราะจะทำให้ไม่ใช้ทรัพยากรของเครื่องที่มีอยู่อย่างจำกัดโดยสูญเปล่า!