300 likes | 494 Views
290210 Data Structures and Algorithms. การเรียกซ้ำ (Recursion) อ.ธารารัตน์ พวงสุวรรณ คณะวิทยาศาสตร์และศิลปศาสตร์ มหาวิทยาลัยบูรพา วิทยาเขตสารสนเทศจันทบุรี thararat@buu.ac.th. การเรียกซ้ำ (Recursion).
E N D
290210 Data Structures and Algorithms การเรียกซ้ำ (Recursion) อ.ธารารัตน์ พวงสุวรรณ คณะวิทยาศาสตร์และศิลปศาสตร์ มหาวิทยาลัยบูรพา วิทยาเขตสารสนเทศจันทบุรี thararat@buu.ac.th
การเรียกซ้ำ (Recursion) • เป็นการนิยามการแก้ปัญหาด้วยขั้นตอนวิธีแบบวนซ้ำ (Repetition Algorithm) โดยมีการเรียกใช้งานตัวมันเอง (Call itself) • เรียกการเขียนโปรแกรมในลักษณะเรียกใช้งานตัวเองว่า Recursive Programming • เรียกฟังก์ชั่นที่มีการเรียกใช้งานตัวมันเองว่า Recursive Function
Approach to writing Repetition Algorithms มี 2 Approach คือ • Use Iteration • Use Recursion • Recursion is a repetitive process in which an algorithm calls itself • Some older languages do not support recursion
Recursive Function ฟังก์ชันเรียกตนเอง จะทำงานได้อย่างสมบูรณ์ จะต้องมีองค์ประกอบ ดังต่อไปนี้ • มีการเรียกใช้ฟังก์ชันที่มีชื่อเป็นชื่อฟังก์ชันของตนเอง เช่น ชื่อของตนคือ factorial ก็จะมีการเรียกใช้ฟังก์ชัน factorial() ภายในซึ่งอาจจะอยู่ในส่วนคำสั่งหรือเป็นองค์ประกอบในนิพจน์ • มีการรับค่าเข้าทางพารามิเตอร์ของฟังก์ชัน โดยค่าดังกล่าวจะถูกนำไปใช้ภายในฟังก์ชันเอง ซึ่งผลของการคำนวณบางส่วนจะถูกนำไปใช้เวลาที่มีการเรียกใช้”ชื่อ”ฟังก์ชันตนเองภายในตัวฟังก์ชัน
Recursive Function • มีการส่งผลการคำนวณกลับ ซึ่งผลดังกล่าวจะนำไปใช้ในการคำนวณในฟังก์ชันเรียกตนเองหรืออาจจะส่งกลับให้กับโปรแกรม • มีจุดสิ้นสุดของการเรียกตนเอง ฟังก์ชัน เรียกตนเองจะทำงานไม่ได้หากไม่มีช่องทางให้โปรแกรมหยุดการเรียกตนเองในขั้น ใดขั้นหนึ่ง เพราะจะเกิดการเรียกตนเองแบบไม่มีสิ้นสุด
Recursive Programming • บางปัญหาสามารถที่จะเขียนในรูปแบบของ recursion จะง่ายกว่า หลักการแก้ปัญหาในรูปแบบ recursion • 1. นิยามปัญหาในรูปการเรียกตัวเอง • 2. มีเงื่อนไขสำหรับจบการทำงาน • “One important requirement for a recursive algorithm to be • correct is that it not generate an infinite sequence of call on itself”
ลักษณะของ Recursive function • call itself directly • call itself indirectly หรือเรียกว่า Recursive chains
Recursive Programming ตัวอย่าง S(n) = 1+2+3+4+5+6+7+…+n S(1) = 1 S(2) = 1+2 = S(1)+2 S(3) = 1+2 +3 = S(1)+2+3 = S(2)+3 จะได้ S(n) = S(n-1)+n
Recursive Programming ตัวอย่าง recursive function ที่ไม่ควรทำ int main(void) { printf(“The universe is never ending\n”); main(); return 0; } //an infinite sequence of call on itself
Recursive chains ตัวอย่างของ Recursive chains a(formal parameters) b(formal parameters) { { . . . . . . b(arguments); a(arguments); } /* end a */ } /* end b */ “Both a and b are recursive”
A Classic Recursive Case • Factorial เป็น case study • Factorial(n) = 1 if n=0 n x (n-1) x (n-2) x ... x 3 x 2 x 1if n >0
Iterative Factorial Algorithm Algorithm iterativeFactorial (n) Calculates the factorial of a number using a loop Pre n is the number to be raised factoriallly Post n! is returned Return factN เป็นค่า n! 1 set i to 1 2 set factN to 1 3 loop( i <= n) 1 set factN to factN * i 2 increment i 4 end loop 5 return factN end iterativeFactorial
Recursive Factorial Algorithm Algorithm recursiveFactorial (n) Calculates factorial of a number using recursion Pre n is the number to be raised factoriallly Post n! is returned Return ค่า n! 1 if (n equal 0) 1 return 1 2 else 1 return (n * recursiveFactorial (n-1)) 3 end if end recursiveFactorial
การคำนวณหาค่าแฟกทอเรียลของจำนวนเต็มบวกการคำนวณหาค่าแฟกทอเรียลของจำนวนเต็มบวก การนิยามแบบ iterative n! = n * (n-1) * (n-2) * ... 1 อาจเขียนคำจำกัดความของฟังก์ชัน ได้ว่า n! = 1if n ==0 n! = n * (n-1) * (n-2) * ... * 1 if n > 0
Iterative programming //Function for calculating factorial of integer long int fact(int n) { int x; prod = 1; for(x = n; x > 0; x--) prod = prod * x; return(prod); }
การนิยามแบบ Recursion • เขียนปัญหาในรูปการเรียกตัวเอง • n! = n * (n-1)! • อาจเขียนคำจำกัดความของฟังก์ชัน ได้ว่า • n! = 1if n ==0 • n! = n * (n-1)! if n > 0 • 2. หาเงื่อนไขสำหรับจบการทำงาน • คือ เมื่อเรียกตัวเองจนถึง 0! = 1
Recursive programming //Function for calculating factorial of integer long int fact(int n) { if(n == 0) //condition for end calling itself return(1) else return(n * fact(n-1)); } Recursion
Recursive programming “Recursive function จะทำงานในลำดับที่กลับกันกับเวลาเรียกใช้” จากโปรแกรมหาค่าแฟกทอเรียลแบบ recursion การเรียกใช้จะเป็นลำดับดังนี้ n! = n * (n-1)! (n-1)! = (n-1) * (n-2)! (n-2)! = (n-2) * (n-3)! ......... 2! = 2 * 1! 1! = 1 * 0! 0! = 1
Recursive programming ค่าที่ส่งกลับมาจะเป็นลำดับที่กลับกัน ดังนี้ 0! = 1 1! = 1 * 0! = 1 2! = 2 * 1! = 2 * 1 = 2 3! = 3 * 2! = 3 * 2 = 6 4! = 4 * 3! = 4 * 6 = 24 ........ n! = n * (n-1)! = ......
Recursive programming ดังนั้น ส่ง 4 เข้าไปให้ฟังก์ชัน พอเรียกฟังก์ชัน จะได้ return(4 * return(3 * return(2 * return(1 * return(1); จะเห็นว่า ค่าส่งกลับจะเป็น return(4*3*2*1*1)
Recursive Example • เป็นตัวอย่างของการแก้ปัญหาแบบ Recursion • Greatest Common Divisor (GCD) • Fibonacci Numbers • Towers of Hanoi
Greatest Common Division(GCD) • เป็นฟังก์ชันทางคณิตศาสตร์ ที่รู้จักกันว่า การหาตัวหารร่วมมาก (ห.ร.ม.) • gcd ของจำนวนเต็มซึ่งไม่เป็น 0 พร้อมกัน คือจำนวนเต็มที่มากที่สุดที่หารทั้งสองจำนวนลงตัว • เช่น gcd ของ 10 กับ 25 คือ 5 • มีประโยชน์ในการทำเศษส่วนให้เป็นเศษส่วนอย่างต่ำ • ใช้ Euclidean Algorithm ในการหา gcd ของจำนวนเต็มที่ไม่เป็นค่าลบ
Greatest Common Division(GCD) • gcd (a,b) = a if b = 0 b if a = 0 gcd (b, a mod b) otherwise
Greatest Common Division(GCD) Algorithm gcd (a, b) Calculates greatest common division using the Euclidean algorithm Pre a and b are positive integers greater than 0 Post greatest common divisor returned .............................................. ............................................... ................................................. ................................................. .................................................. .................................................. ................................................. end gcd
การหา Fibonacci numbers • การหาชุดของ Fabonacci series จะต้องทราบตัวเลข 2 ตัวแรก นิยาม Fib(n) = n if n = 0 or n = 1 Fib(n) = Fib(n-1) + Fib(n-2) if n > 1
Fibonacci numbers เขียนเป็น recursive function ได้ว่า int fib(int n) { int x,y; if(n<= 1) return(n); x = fib(n-1); y = fib(n-2); return(x+y); }
Tower of Hanoi Problem B C A เป้าหมาย ต้องการเคลื่อนย้าย disk ทั้งหมดไปไว้อีก pegหนึ่ง ข้อกำหนด • เคลื่อนย้ายครั้งละ 1 diskเท่านั้นโดยเคลื่อนย้ายจาก disk บนสุดก่อน • - ไม่อนุญาตให้ disk ที่ใหญ่กว่าซ้อนบน disk ที่เล็กกว่า
จากรูปดังกล่าว หากเราต้องการเคลื่อนย้าย disk ทั้งหมดจาก A ไป C Recursive solution for Towers of Hanoi Problem • if n==1, move the single disk from A to C and stop • 2. Move the top n-1 disks from A to B, using C as auxiliary • 3. Move the remaining disk from A to C • 4. Move the n-1 disks from B to C, using A as auxiliary
Efficiency of recursion โดยทั่วไป โปรแกรมที่มีลักษณะnonrecursiveการประมวลผลจะมี ประสิทธิภาพดีกว่าโปรแกรมที่มีลักษณะ recursive ในด้านของเวลาและพื้นที่ หน่วยความจำ (space)แต่ลักษณะบางโปรแกรมก็เหมาะที่จะเขียนแบบ recursive เพราะจะทำให้ง่ายกว่าและเกิดข้อผิดพลาดได้น้อยกว่าแบบ nonrecursive ข้อดีของ recursive programming - เขียนได้สั้น ง่าย - มองเห็นแนวทางการแก้ปัญหาได้ชัดเจน - ใช้เวลาไม่มากในการเขียนโปรแกรม
ข้อเสียของ recursive programming บางปัญหาไม่เหมาะที่จะแก้ปัญหาด้วย recursive programming เนื่อง จากทำให้มีการทำงานที่ซ้ำซ้อน เช่น การหา Fibonacci number Fib(n) = n if n = 0 or n = 1 Fib(n) = Fib(n-1) + Fib(n-2) if n > 1 ตัวอย่าง Fib(5) = Fib(4) + Fib(3) Fib(4) = Fib(3) + Fib(2) Fib(3) = Fib(2) + Fib(1) Fib(2) = Fib(1) + Fib(0)