วิธีใช้ Python Recursion
Python recursion เป็นหัวข้อที่น่ากลัวสำหรับผู้เริ่มต้น มาถอดมายาความเชื่อว่าการเรียกซ้ำ (recursion) ยากลำบากโดยการกำหนดคำจำกัดความ Recursion คือวิธีการเขียนโปรแกรมที่ฟังก์ชันเรียกตัวเอง
聽起來简单, 对吧? 当你掌握了它, 递归并不是一个困难的概念。
ในบทช่วยสอน Python นี้ เราจะพูดถึง recursion และวิธีการทำงาน เราจะเดินทางผ่านตัวอย่างของ recursion โดยใช้ฟังก์ชันแฟกทอเรียลเพื่อช่วยให้คุณเริ่มต้นกับวิธีการเขียนโปรแกรมนี้ได้
Recursion คืออะไร?
Recursion คือการที่คุณกำหนดสิ่ง gìในรูปแบบของตัวมันเอง
ฟังก์ชันเรียกซ้ำแก้ปัญหาโดยการเรียกตัวเองซ้ำอีกครั้ง พฤติกรรมนี้รองรับในภาษาโปรแกรมมิ่งหลักๆ เช่น Python พวกมันเป็นส่วนสำคัญของวิทยาการคอมพิวเตอร์และวิทยาการข้อมูล
Recursion มีประโยชน์เมื่อคำตอบของปัญหาสามารถหาได้โดยการแยกมันออกเป็นปัญหาย่อยๆ ซึ่งทั้งหมดใช้สูตรเดียวกัน ปัญหาเหล่านี้มักเรียกว่า "recursive algorithms" กุญแจสู่การแก้ไขอยู่ที่ชื่อ!
Iterative vs. Recursive
มีสองวิธีในการแก้อัลกอริทึม: แบบวนซ้ำ (iteratively) หรือแบบเรียกซ้ำ (recursively)
วิธีแก้ปัญหาแบบวนซ้ำถูกมองว่า "มีพลังแต่ไม่สวยงาม" พวกมันทำงานเสร็จ แต่ไม่ได้ทำในวิธีที่ซับซ้อนที่สุด เพื่อเข้าใจ recursive algorithms อย่างถูกต้อง เราต้อง看ฟังก์ชันแบบวนซ้ำ
ฟังก์ชันแบบวนซ้ำคือฟังก์ชันที่แก้ปัญหาโดยใช้ลูป มันจะ execute โค้ดภายในลูปจนกว่าลูปจะเสร็จ ฟังก์ชันเรียกซ้ำคือฟังก์ชันที่แยกปัญหาออกเป็นส่วนย่อยและแก้แต่ละส่วนโดยการเรียกตัวเอง
แฟกทอเรียล: ตัวอย่างแบบวนซ้ำ (Iterative Example)
แฟกทอเรียลเป็นวิธีที่ดีในการสาธิต recursion และการคิดแบบวนซ้ำ ในคณิตศาสตร์ แฟกทอเรียลคือผลรวมของตัวเลขและทุกตัวเลขก่อนหน้าคูณรวมกัน
แฟกทอเรียลของ 5 เท่ากับ 5 * 4 * 3 * 2 * 1 แฟกทอเรียลของ 2 เท่ากับ 2 * 1
เพื่อคำนวณแฟกทอเรียล เราสามารถเขียนฟังก์ชันแบบวนซ้ำได้:
def factorial(number): total = 1 for n in range(1, number + 1): total = total * n return total
ฟังก์ชันนี้ใช้ลูป for เพื่อวนซ้ำผ่านตัวเลขทั้งหมดในช่วงของ 1 และตัวเลขที่เราระบุบวก 1 สำหรับแต่ละการวนซ้ำ ตัวเลขที่ลูปกำลังวนซ้ำจะถูกคูณกับ total มาเรียกฟังก์ชันของเราเพื่อหาแฟกทอเรียล:
answer = factorial(4) print(answer)
โค้ดของเราคืนค่า: 24 เพื่อให้ได้คำตอบนี้ โค้ดของเรารัน:
- 1 * 1 = 1
- 2 * 2 = 4
- 4 * 3 = 8
- 8 * 4 = 24
ตามที่เห็น โค้ดของเราคูณ 4 กับตัวเลขทั้งหมดที่ต่ำกว่ามันและตัวมันเอง
โค้ดนี้ทำงานได้ ข้อเสียเพียงอย่างเดียวคือมันไม่ได้สวยงามเท่าที่ควร นี่คือที่ที่ฟังก์ชันเรียกซ้ำเข้ามาช่วย
แฟกทอเรียล: ตัวอย่าง Recursion
มาเขียนฟังก์ชันเรียกซ้ำที่คำนวณแฟกทอเรียล เปิดไฟล์ Python ใหม่และวางโค้ดต่อไปนี้:
def factorial(number): if number == 1: return 1 else: return (number * factorial(number - 1))
โค้ดนี้ใช้วิธีแบบเรียกซ้ำ เมื่อฟังก์ชันนี้รัน คำสั่ง "if" จะถูก execute คำสั่งนี้ตรวจสอบว่าตัวเลขที่ส่งให้ฟังก์ชันเท่ากับ 1 หากใช่ ฟังก์ชันของเราคืนค่า 1 มิฉะนั้น แฟกทอเรียลของตัวเลขของเราจะถูกคำนวณ
การคำนวณนี้ทำงานโดยการคูณตัวเลขที่ส่งให้ฟังก์ชันด้วยแฟกทอเรียลของตัวเลขก่อนหน้า ฟังก์ชันนี้ถูกเรียกซ้ำๆ จนกว่า "number" จะเท่ากับ 1 ทุกครั้งที่ฟังก์ชันถูกเรียก ค่าของ "number" จะลดลง 1
มาให้โค้ดของเราลองกับตัวเลข 4:
answer = factorial(4) print(answer)
คำตอบ 24 ถูกคืนค่า คำตอบของเราถูกต้อง เหมือนกับตัวอย่างก่อนหน้า เราได้หาคำตอบของปัญหานี้แบบเรียกซ้ำแทนที่จะเป็นแบบวนซ้ำ
คุณยังต้องการความช่วยเหลือเล็กน้อย? มาเดินทางผ่านตัวอย่างอีกตัวอย่างของ recursion
Recursion กับลำดับฟีโบนัชชี (Fibonacci Sequence)
ลำดับฟีโบนัชชีเป็นลำดับคณิตศาสตร์ที่ตัวเลขแต่ละตัวคือผลรวมของสองตัวเลขก่อนหน้า ลำดับนี้เริ่มต้นด้วย: 0, 1, 1, 2, 3, 5, 8, 13, และต่อไป
ลำดับนี้บวกสองตัวเลขเพื่อหาตัวเลขถัดไป ทำให้มันเหมาะสำหรับ recursion
เปิดไฟล์ Python และวางโค้ดนี้:
def fibonacci(number): if number <= 1: return number else: return(fibonacci(number - 1) + fibonacci(number - 2))
โค้ดนี้จะคำนวณผลรวมของสองตัวเลขก่อนหน้าในรายการ ตราบใดที่ "number" มากกว่า 1 มิฉะนั้น "number is returned" ตอนนี้ มาเรียกฟังก์ชันของเรา:
executions = 5 print("Fibonacci Sequence:") for number in range(executions): print(fibonacci(number)) ตัวแปร executions ติดตามว่าต้องการคำนวณตัวเลขในลำดับฟีโบนัชชีกี่ตัว เราใช้มันเพื่อสร้างลูป for ซึ่งเรียกฟังก์ชัน fibonacci() ของเราสำหรับแต่ละตัวเลขในช่วงของ 1 และค่าของ "executions"
ก่อนที่ลูป for จะเริ่ม เราพิมพ์ "Fibonacci Sequence:" ไปยังคอนโซล ในตัวอย่างนี้ ลูป "for" ของเรา execute:
fibonacci(1) fibonacci(2) fibonacci(3) fibonacci(4) fibonacci(5)
มารันโค้ดของเราทั้งหมดและ看看发生什么:
Fibonacci Sequence: 0 1 1 2 3
โค้ดของเราคำนวณตัวเลขห้าตัวแรกในลำดับฟีโบนัชชี เราสามารถคำนวณตัวเลขมากขึ้นได้โดยเพิ่มค่าของ "executions"
ความลึกของ Recursion และเงื่อนไขฐาน (Base Conditions)
ฟังก์ชันเรียกซ้ำต้องมีเงื่อนไขฐาน (base condition) นี่คือเงื่อนไขที่หยุด recursion เมื่อกรณีฐาน (base case) เฉพาะเจาะจงถูกตอบสนอง โดยไม่มีฟังก์ชันฐาน ลูปไม่รู้จบจะถูกสร้างขึ้น
ฟังก์ชันเรียกซ้ำสามารถ execute ตัวเองได้ไม่เกิน 1,000 ครั้งโดยค่าเริ่มต้น เมื่อถึงขีดจำกัดนี้ ข้อผิดพลาดแบบนี้จะปรากฏ:
RecursionError: maximum recursion depth exceeded
นี่คือเงื่อนไขฐานสำหรับโปรแกรมฟีโบนัชชีของเรา:
... if number <= 1: return number …
เงื่อนไขนี้ตรวจสอบว่าค่าของ "number" ภายในโปรแกรมฟีโบนัชชีของเราเท่ากับหรือน้อยกว่า 1 หากใช่ ค่าของ "number" จะถูกคืนค่า มิฉะนั้น ฟังก์ชันเรียกซ้ำจะเริ่มต้น
ทำไมควรใช้ Recursion?
ข้อได้เปรียบของการใช้ recursion เหนือฟังก์ชันแบบวนซ้ำคืออะไร? ทางเทคนิค ทั้งสองวิธีสามารถบรรลุผลลัพธ์เดียวกันได้ ข้อได้เปรียบของ recursion คือมันอ่านง่ายกว่า
เมื่อคุณเห็นฟังก์ชันเรียกซ้ำ มันชัดเจนว่าคำตอบของปัญหาอยู่ที่การแยกมันออกเป็นส่วนย่อย ในขณะที่ลูปแบบวนซ้ำบางครั้งอาจเร็วกว่า ฟังก์ชันเรียกซ้ำมักถูกเลือกเนื่องจากความอ่านง่าย
เพราะฟังก์ชันเรียกซ้ำอ่านง่าย จึงง่ายต่อการบำรุงรักษาและแก้ไขข้อบกพร่อง (debug)ด้วย นี่มีประโยชน์โดยเฉพาะเมื่อคุณเขียนอัลกอริทึมซับซ้อนที่อาจเข้าใจยาก
สรุป
ฟังก์ชันเรียกซ้ำคือฟังก์ชันที่เรียกตัวเองเพื่อหาคำตอบของปัญหา
ฟังก์ชันเรียกซ้ำแยกปัญหาออกเป็นหลายส่วนและแก้ส่วนหนึ่งของปัญหาต่อการวนซ้ำ ฟังก์ชันเรียกซ้ำมักใช้คำนวณแฟกทอเรียลและตัวเลขในลำดับฟีโบนัชชี พวกมันยังใช้ในอัลกอริทึมหลายอย่าง
ตอนนี้คุณพร้อมที่จะเริ่มทำงานกับฟังก์ชันเรียกซ้ำใน Python แล้ว