บทความอื่นๆ ในชุดของ Intro to Programming & Algorithm
- บทนำฉบับรวบรัด! ความรู้พื้นฐานก่อนเริ่มเขียนโปรแกรม
- รู้จักกับตัวแปลภาษา Compiler และ Interpreter
- Algorithm (1) – ขั้นตอนวิธี หัวใจสำคัญของการเขียนโปรแกรม
- Algorithm (2) – อัลกอริทึมในมุมมองของคอมพิวเตอร์
- Algorithm (3) – Decision การสร้างทางเลือกให้โปรแกรม
- Algorithm (4) – loop สั่งให้โปรแกรมทำงานซ้ำๆ
- ตัวอย่างการสร้าง Algorithm
คอมพิวเตอร์เป็นเครื่องจักรที่สร้างขึ้นมาเพื่อ "แก้ปัญหา" ให้กับพวกเรา แต่คอมพิวเตอร์จะแก้ปัญหาไม่ได้ ถ้ามันไม่รู้วิธีว่าจะแก้ยังไง จริงมั้ย?
การเขียนโปรแกรมก็เหมือนกับการสอนวิธีแก้ปัญหาต่างๆ ให้คอมพิวเตอร์
นั่นแปลว่าหัวใจสำคัญของการเขียนโปรแกรมก็คือ...
Problem Solving
หรือศาสตร์แห่งการแก้ปัญหา ในวิชาการเขียนโปรแกรมถ้าใครคิดว่าหัวใจหลักของวิชานี้คือการ เขียนโค้ด ละก็ ผิดแล้วล่ะ! นี่คือวิชาที่ว่าด้วยการ
"การคิดวิธีการแก้ปัญหาต่างๆ"
แต่วิธีการแก้ปัญหาที่ต้องสอนในวิชาการเขียนโปรแกรม เราจะเรียกมันว่า
Algorithm
(อ่านว่า "อัลกอริทึม")
การแก้ปัญหาแบบเป็นขั้นตอนๆ เป็นสเต็ปๆ
วิธีการแก้ปัญหาแบบนี้สร้างขึ้นมาสำหรับอะไรก็ตามที่ทำตามคำสั่งเราโดยไม่มีสมอง
คือต้องเข้าใจก่อนว่าคอมพิวเตอร์ทำตามคำสั่งเราก็จริงๆ แต่ทำตามแบบ ทำตามจริงๆ นะ มันจะไม่คิดอะไรทั้งนั้น
เช่นถ้าเราสั่งให้คนเดินไปเรื่อยๆ แล้วเจอข้างหน้าเป็นหน้าผา แน่นอนว่าคนจะเดินไปถึงปลายหน้าผาแล้วเอะใจว่าฉันไม่ควรจะเดินต่อไปนะ แต่ถ้าเป็นคอมพิวเตอร์ แน่นอนว่ามันจะไม่หยุดเดิน เพราะเราไม่ได้สั่งว่าถ้าเจอทางที่เดินต่อไปไม่ได้ ต้องหยุดด้วยนะ ยังไงล่ะ
นั่นคือถ้ามองภาพรวมๆ แล้ว การจะสร้างโปรแกรมขึ้นมาได้จะต้องผ่าน 3 สเต็ปคือ
- คิด algorithm วิธีแก้ปัญหาจากโจทย์ที่ได้รับมา (หรือก็คือวิธีคิด/ตีความโจทย์นั่นเอง)
[ระดับความยาก: ★★★] - เขียนโค้ดจาก algorithm ที่คิดขึ้นมา (ใช้เขียนด้วยภาษา เช่น C, Java, Python)
[ระดับความยาก: ★★] - คอมไพล์ออกมาเป็น execution file ที่เอาไปรันได้
[ระดับความยาก: ★]
Algorithm ขั้นตอนวิธี
คำว่าอัลกอริทึม มาจากชื่อของนักคณิตศาสตร์ชาวเปอร์เซียในช่วงศตวรรษที่ 9 ชื่อว่า Muhammad al-Khwarizmi เขาเป็นใครยังไม่ต้องสนใจก็ได้ เพราะไม่ค่อยเกี่ยวกับเนื้อหาของเราเท่าไหร่ แค่อยากบอกให้รู้ว่าเท่านั้นเอง (ฮา)
กฎคร่าวๆ สำหรับการสร้างวิธีการแก้ปัญหาตามสไตล์ Algorithm คือ
- ต้องเป็นลำดับ/ขั้นตอน
- คำที่ใช้พยายามให้เรียบง่ายเข้าไว้ เข้าใจง่าย
- เลี่ยงการใช้คำกำกวม ที่แต่ละคนอาจจะตีความออกมาไม่เหมือนกัน
อ่านไปอาจจะไม่เข้าใจ มาดูตัวอย่างกันดีกว่า สมมุติเราบอกว่า
"ถ้าฝนทำท่าจะตก --> ให้เอาร่มออกไปด้วย"
ประโยคแบบนี้อาจจะถือว่าเป็น algorithm ได้ เพราะเป็นการสั่งแบบเป็นลำดับขั้น (ถ้า xxx แล้ว yyy) แต่ข้อความที่ใช้กำกวม คือถ้าเราเอาประโยคนี้ไปสั่งคน 100 คน แต่ละคนอาจจะชะเง้อหน้าไปมองฟ้า แล้วตัดสินใจไม่เหมือนกันก็ได้ว่าฟ้าครึ้มเท่านี้ บางคนบอกว่าฝนน่าจะตก อีกส่วนหนึ่งบอก ไม่น่าจะตกหรอกนะ
จึงถือว่าเป็นการกำหนดเงื่อนไขของ algorithm ที่ไม่ดี!
แล้วถ้าจะแก้ต้องทำยังไง ?
"ถ้าความชื้นสัมพัทธ์ในอากาศมีค่ามากกว่า 85%
--> หมายความว่าฝนน่าจะตก
--> ให้เอาร่มออกไปด้วย"
ในกรณีนี้ใช้ความชื้นเป็นตัววัด (ค่า 85% เป็นค่าสมมุติขึ้นมานะ) ในเมื่อทุกคนใช้เครื่องวัดความชื้นอ่านค่า ทุกคนก็จะตัดสินใจไปในทางเดียวกัน (ถือว่าทุกคนต้องอ่านค่าจากตัววัดออกมาได้เท่ากันด้วยนะ!)
แต่ algorithm ก็เป็นแค่หลักการ/แนวคิดธรรมดา สำหรับโจทย์ที่มีคำสั่งละเอียดกว่านี้ หรือซับซ้อนกว่านี้ การเขียนเป็นประโยคๆ อาจจะยากและไม่มีหลักการเกินไปหน่อยล่ะ
เขาเลยมีการสร้างเครื่องมือ (Tools) เอาไว้วาดแนวคิดเนี้ยออกมาให้เป็นรูปเป็นร่างได้ ซึ่งค่อนข้างจะวางไว้เป็นแบบมาตราฐาน ทุกคนจะวาดออกมาในรูปแบบเดียวกัน เวลาอ่าน algorithm ที่คนอื่นเขียนมา เราก็สามารถอ่านรูปเรื่องได้ง่ายๆ (จริงๆ ก็...ไม่ง่ายขนาดนั้น ต้องอาศัยการฝึกด้วย)
ที่นิยมกันมีอยู่ 2 ตัวคือ Flowchart และ Pseudocode
Pseudocode
สำหรับ Tool ตัวแรกขอยกตัวอย่างด้วย "ซูโดโค้ด" (ถ้าใครเรียนชีวะมาเยอะๆ อาจจะคุ้นๆ กับคำว่า Pseudo ที่แปลว่า “เทียม” ซึ่งจะอ่านว่า "สูโด" ตามที่นิยมในหนังสือชีวะก็ไม่มีใครว่าอะไร) แปลว่า "โค้ดเทียม"
ลักษณะของซูโคโค้ดคือเราจะเขียนสำคัญต่างๆ ด้วยภาษาคน ลิสต์เป็นข้อๆ ไปเรื่อยๆ ว่าต้องทำอะไรบ้าง (แน่นอน อย่าลืมนะว่าถึงจะเขียนเป็นภาษาคนได้ แต่ต้องไม่กำกวมด้วยล่ะ)
ตัวอย่างเช่น
Ex. อยากเช็กว่าตัวเลขเป็น Even หรือ Odd หรือก็คือเรามีวิธีเช็กว่าตัวเลขตัวนี้เป็น เลขคู่ หรือ เลขคี่ ยังไง
ถ้าคิดแบบคน ก็ดูจะไม่ยากจะ ก็เลขตัวไหนที่ลงท้ายด้วย 0 2 4 6 8 ก็เป็นเลขคู่ ส่วน 1 3 5 7 9 ก็เป็นเลขคี่ไง
แต่วิธีการแบบนี้เราเอามาใช้กับคอมพิวเตอร์ไม่ได้
ลองมาดูวิธีคิดแบบ algorithm กัน เราสามารถเขียนซูโดโค้ดได้ดังนี้
1. หารตัวเลขตัวนั้นด้วย 2 → เรียกผลหารว่า X 2. ถ้า X เป็น Integer(จำนวนเต็ม) → "Even" 3. ถ้าไม่ → "Odd"
ในโจทย์ข้อนี้ เราสร้างลำดับคำสั่งโดยใช้หลักการแยกเลขคู่กับเลขคี่ด้วยการหาร ถ้าหารแล้วผลการออกมาเป็นจำนวนเต็ม เช่น 8/4 = 2 จะได้ว่า 8 เป็นเลขคู่ แต่ถ้าไม่ เช่น 9/2 = 4.5 มีจุด ไม่ใช่จำนวนเต็ม สรุปว่าเป็นเลขคี่
แต่ algorithm อาจจะไม่ได้มีแค่วิธีเดียวนะ
เราสามารถสร้างขั้นตอนการแก้ปัญหาเดียวกันหลายแบบได้
เช่นในตัวอย่างนี้ มีแนวคิดอื่นมั้ย? สำหรับการเช็กว่าตัวเลขเป็น Even หรือ Odd ?
ตัวอย่าง algorithm แบบอื่นๆ ที่สามารถแก้ปัญหาได้เหมือนกันเลย แค่คิดกันคนละอย่าง
1. module ตัวเลขตัวนั้นด้วย 2 → เรียกผลหารเอาเศษนี้ว่า X 2. ถ้า X เป็น 0 → "Even" 3. ถ้า X เป็น 1 → "Odd"
ก่อนจะอธิบาย ต้องถามก่อนเลยว่ารู้จัก modulo หรือ mod (ออกเสียงว่า มอดูโล หรือ ม๊อด) รึเปล่า?
Modulo หารเอา'เศษ'
mod หรือที่ภาษาโปรแกรมส่วนมากใช้สัญลักษณ์ %
(อย่าไปมองว่ามันคือเปอร์เซ็นนะ) เป็นเครื่องหมายทางคณิตศาสตร์ที่เอาไว้หาเศษจากการหาร คือปกติแล้วเวลาเราหารเลข สิ่งที่ได้คือผลหาร แต่ในเคสของ mod เราจะไม่ได้ผลหาร แต่ได้เศษที่เหลือแทน
เช่น
7 / 3 = 2 แต่เหลือเศษ 1 ดังนั้นจะเขียนอีกอย่างได้ว่า
7 % 3 = 1 นั่นเอง
ป.ล.ใครยังงงๆ อยู่ ลองกลับไปอ่านเรื่องวิธีการหารแบบ "หารยาว" ดูนะ
สำหรับโปรแกรมเมอร์ operator mod (%) นี่ถือเป็นหนึ่งใน operator สำคัญในการคำนวณเลย ถ้าคนปกติใช้ +
, -
, *
, /
เป็นหลัก ... โปรแกรมเมอร์ก็จะใช้ +
, -
, *
, /
, %
ดังนั้นฝึกการใช้ mod ไว้ให้ดีๆ ล่ะ
ไหนมีใครคิดวิธีอื่นออกอีกมั้ย?
โอเค! เดี๋ยวลองให้วิธีแก้ปัญหาอีกแบบเอาไว้ดูเป็นตัวอย่างละกัน
1. หารตัวเลขตัวนั้นด้วย 2 → เรียกผลหารว่า X 2. Round X (ปัดเศษทิ้งไป) 3. คูณ X ด้วย 2 → เรียกผลคูณว่า Y 4. ถ้า Y มีค่าเท่ากับ ตัวเลขตัวนั้น → "Even" 5. ถ้าไม่เท่า → "Odd"
ตัวอย่างสุดท้ายใช้วิธีการว่าถ้าเราจับตัวเลขตัวนึงมาหารด้วย 2 ผลหารออกมาเท่าไหร่ให้ปัดเศษทิ้ง (ถ้าเป็นเลขคี่เศษการหาร 0.5 จะหายไป) เช่น
9 / 2 = 4.5 แล้วปัดเศษทิ้งจะเหลือ 4 ซึ่ง 4 เหมือนคูณ 2 จะได้ 8 ซึ่งมันไม่เท่ากับ 9 สรุปว่า 9 เป็นเลขคี่
(ในปัญหานี้ solution ที่เหมาะกับการเขียนโปรแกรมที่สุดคือ solution ที่ 2 ที่ใช้การ modulo นะ เพราะเมื่อเราแปลงความคิดพวกนี้ให้เป็นโค้ดคอมพิวเตอร์ หรือ Programming Language มันจะเขียนได้ง่ายที่สุด!)
Flowchart
หรือ "ผังงาน" ในภาษาไทย (แนะนำว่าใช้ทับศัพท์ว่า "โฟลชาร์ต" ดีกว่านะ) เป็น Tool อีกตัวที่เอาไว้วาด algorithm
สำหรับ pseudocode เมื่อกี้ถึงจะเขียนง่าย แต่ถ้าวิธีการแก้ปัญหาเริ่มใหญ่ขึ้น การเขียนก็จะเริ่มยากขึ้น (a.k.a. เขียนออกมาแล้วอ่านไม่ค่อยรู้เรื่องนั่นแหละ) วิธีการเขียน algorithm ด้วย flowchart จึงเป็นวิธีที่เราชอบมากกว่า
สำหรับ flowchart จะไม่ใช้การเขียนเป็นข้อๆ แบบ pseudocode แต่จะออกเชิง วาดรูป มากกว่า
Flowchart จะใช้สัญลักษณ์ง่ายๆ แทนคำสั่งต่างๆ ซึ่งการวาด flowchart มีหลายมาตราฐาน ในสรุปชุดนี้เลือกตัวที่คอมมอนๆ คือใช้ได้กลางๆ กับทุกมาตรฐานมาสอนนะ
สัญลักษณ์ (Symbol) ที่ใช้หลักๆ จะมีอยู่ 4 แบบ
- วงกลม (หรือวงรีก็ได้นะ) ใช้สำหรับบอกจุดเริ่มและจุดสิ้นสุดของโปรแกรม
- สี่เหลี่ยมด้านขนาน แทนการทำงานบน I/O ที่มีการติดต่อกับผู้ใช้ ไม่ว่าจะเป็น input หรือ output ก็ได้
- สี่เหลี่ยมมุมฉาก แทนการคิดคำนวณหรือ Process ของคอมพิวเตอร์ ในขั้นตอนนี้ผู้ใช้งานจะไม่เห็นค่าอะไรเลย
- สี่เหลี่ยมขนมเปียกปูน (นิยมเรียกกันว่า daimon มากกว่า) เอาไว้สร้างเงื่อนไขทำให้ flowchart แยกออกเป็นหลายๆ ทางได้
มาลองดูกับคำถามเลขคู่เลขคี่เมื่อกี้กันอีกทีนะ
Ex. อยากเช็กว่าตัวเลขเป็น Even หรือ Odd หรือก็คือเรามีวิธีเช็กว่าตัวเลขตัวนี้เป็น เลขคู่ หรือ เลขคี่ ยังไง
จากเดิมที่เราเคยเขียนเป็นข้อๆ เรียงๆ กันแบบนี้
1. module ตัวเลขตัวนั้นด้วย 2 → เรียกผลหารเอาเศษนี้ว่า X 2. ถ้า X เป็น 0 → "Even" 3. ถ้า X เป็น 1 → "Odd"
เราก็จะวาดเป็นสัญลักษณ์เรียงกันแบบนี้แทน
ถ้าสังเกต ก็คือ Flowchart เนี่ยมันก็จะคล้ายๆ กับการเขียน Pseudo-code นั่นแหละ แต่จะเป็นการเอาคำสั่งต่างๆ มาเรียงกันในแบบของ แผนภาพ ซะมากกว่า
และจากประสบการณ์การสอนมาเกือบ 10 ปี น้องๆ แทบจะทุกคนก็บอกว่า Flowchart เนี่ยสามารถทำความเข้าใจได้ง่ายกว่า Pseudo-code มากๆ เพราะแทนที่จะเป็นข้อคำสั่งเรียงๆ กัน อันนี้จะวาดออกมาเป็นรูปภาพทำให้ไล่สายตาตามคำสั่งได้ง่ายกว่านั่นเอง
แต่ยังไงก็ตาม การเขียน algorithm ในบทความนี้ยังไม่ถูกต้อง 100% นัก ซึ่งเราจะพูดถึงรายละเอียดพวกนี้กันต่อในบทความต่อไปนะ
อธิบายได้เข้าใจง่ายมากๆค่ะ