Đệ quy là một khái niệm lập trình thú vị nhưng có thể hơi khó học. Đệ quy chỉ đơn giản có nghĩa là một cái gì đó lặp lại chính nó. Nếu bạn muốn xem một ví dụ thú vị về đệ quy, hãy thử tìm kiếm đệ quy trên Google. Bạn sẽ tìm thấy một quả trứng Phục sinh trong đó các đề xuất kết quả tìm kiếm là đệ quy. Mặt khác, nếu bạn muốn học cách viết mã một hàm đệ quy, hãy đọc tiếp!
Hàm đệ quy là gì?
Một hàm đệ quy là một hàm gọi chính nó. Về cơ bản, bạn tạo một vòng lặp với một hàm. Như bạn có thể tưởng tượng, đây có thể là những hàm khó viết. Bạn không muốn mã của mình chạy mãi mãi.
Tương tự như một vòng lặp, một hàm đệ quy sẽ được điều khiển bởi một điều kiện. Khi điều kiện được đáp ứng, hàm ngừng gọi chính nó, điều này sẽ dừng vòng lặp. Đây là cách bạn có thể tạo một hàm tự gọi mà không cần nó chạy mãi mãi.
Mặc dù một hàm đệ quy hoạt động giống như một vòng lặp, nhưng nó được máy tính thực thi theo cách khác. Vì vậy, một số thuật toán hiệu quả hơn trong một vòng lặp và những thuật toán khác được hưởng lợi từ một hàm đệ quy. Nhưng trước khi xem cách sử dụng một hàm đệ quy, bạn cần biết cách viết một hàm đệ quy.
Cách viết một hàm đệ quy
Tất cả các hàm đệ quy đều có cấu trúc cơ bản giống nhau:
FUNCTION name IF condition THEN RETURN result ELSE CALL FUNCTION name END FUNCTION
Ví dụ trên được viết bằng mã giả. Nó phác thảo cấu trúc của hàm, có thể áp dụng cho bất kỳ ngôn ngữ nào. Để đơn giản hơn, trong bài viết này, chúng tôi sẽ tập trung vào Python.
Điều đầu tiên cần lưu ý về một hàm đệ quy là khi điều kiện được đáp ứng, hàm sẽ thoát khỏi đệ quy. Điều này có nghĩa là khi bạn viết một hàm đệ quy, điều đầu tiên bạn sẽ muốn xác định là khi nào thì dừng đệ quy.
Nếu điều kiện không được đáp ứng, hàm sẽ tự gọi. Vì vậy, nếu bạn muốn gửi thông tin đến vòng lặp tiếp theo, bạn sẽ phải gửi nó dưới dạng một đối số trong hàm của mình. Điều này có thể cung cấp cho các hàm đệ quy nhiều quyền lực hơn.
Liên quan: Chức năng trong lập trình là gì?
Ví dụ về hàm đệ quy trong Python
Sẽ dễ dàng hơn nhiều để hiểu cách hoạt động của đệ quy khi bạn thấy nó hoạt động. Để chứng minh điều đó, hãy viết một hàm đệ quy trả về giai thừa của một số.
Các thừa số trả về tích của một số và tất cả các số nguyên trước nó. Ví dụ: giai thừa của 5 là 5 x 4 x 3 x 2 x 1 hoặc, 120.
def factorialFunction(numberToMultiply): if numberToMultiply == 1 : return 1 else : return numberToMultiply * factorialFunction(numberToMultiply - 1) result = factorialFunction(3) print(result) //Outputs: 6
Chương trình trên sẽ cung cấp cho bạn kết quả là 6, là giai thừa của số 3. Điều này có thể hơi khó hiểu lúc đầu. Nó sẽ hữu ích nếu chúng ta chạy qua chương trình từng bước.
- Khi hàm được gọi, numberToMultiply bằng 3.
- Điều kiện không được đáp ứng, vì vậy chúng tôi đi vào điều kiện khác .
- Hàm của chúng ta trả về 3 * nhưng sau đó bị tạm dừng. Nó phải gọi chính nó để xác định phần còn lại của giá trị mà nó đang trả về.
- Khi hàm được gọi lần này, giá trị của numberToMultiply bằng 2.
- Điều kiện không được đáp ứng, vì vậy chúng tôi đi vào điều kiện khác.
- Hàm của chúng ta trả về 2 * nhưng sau đó bị tạm dừng. Nó phải gọi chính nó để xác định phần còn lại của giá trị mà nó đang trả về.
- Hàm lại được gọi. Lần này, giá trị của numberToMultiply bằng 1.
- Nếu điều kiện của chúng tôi được đáp ứng. Hàm trả về 1.
- Hàm từ bước 6 hiện có thể trả về 2 * 1 cho hàm ở bước 3.
- Hàm ở bước ba hiện có thể trả về 3 * 2 * 1, là 6.
Đệ quy là một khái niệm phức tạp. Có thể hữu ích nếu coi nó giống như việc xếp chồng một chức năng lên trên một chức năng khác. Khi một chức năng cuối cùng được giải quyết, nó có thể gửi thông tin trở lại ngăn xếp, cho đến khi tất cả các chức năng có câu trả lời.
Đây thực sự là những gì máy tính của bạn làm. Khi bạn gọi hàm, nó sẽ được lưu trong bộ nhớ cho đến khi nó được trả về. Điều này có nghĩa là các hàm đệ quy có thể sử dụng nhiều bộ nhớ hơn một vòng lặp.
Vì vậy, có thể không hiệu quả nếu viết các vòng lặp dưới dạng các hàm đệ quy, nhưng đó là một cách tuyệt vời để thực hành xây dựng chúng. Bạn sẽ có thể mã các vòng lặp dưới dạng các hàm đệ quy với kết quả tương t��.
Ví dụ về cách chuyển đổi một vòng lặp thành một hàm đệ quy
print("Enter an even number:") i = int(input()) while (i % 2) != 0 : print("That number is not even. Please enter a new number:") i = int(input())
Vòng lặp này cũng có thể được viết một cách đệ quy như sau:
def recursiveFunction(number) : if (number % 2) == 0 : return number else: print("That number is not even. Please enter a new number:") recursiveFunction(int(input())) print("Enter and even number:") i = recursiveFunction(int(input()))
Bước đầu tiên là xác định khi nào bạn muốn chức năng của mình dừng lại. Trong trường hợp này, chúng tôi muốn nó dừng lại khi nhập một số chẵn. Trong ví dụ của chúng tôi, số theo dõi đầu vào của người dùng. Nếu họ nhập một số chẵn, chúng tôi trả về số đó. Nếu không, chúng tôi sẽ tiếp tục yêu cầu một số mới.
Để thiết lập vòng lặp, chúng ta gọi lại hàm của mình. Nhưng lần này, số chúng ta chuyển sang hàm tiếp theo là số mới do người dùng nhập vào. Lần gọi hàm tiếp theo sẽ kiểm tra số.
Đây là một chức năng thực sự tồi tệ! Có, nó đang kiểm tra xem số có chẵn không, giống như vòng lặp của chúng tôi, nhưng nó không hiệu quả. Mỗi khi người dùng nhập một số lẻ, hàm sẽ được lưu trong bộ nhớ và một hàm mới được gọi. Nếu bạn làm điều này đủ lần, bạn sẽ hết bộ nhớ!
Liên quan: Các ví dụ Python cơ bản sẽ giúp bạn học nhanh
Một ví dụ trong thế giới thực về một hàm đệ quy
Các ví dụ trên là những ví dụ điển hình về thời điểm không sử dụng đệ quy. Vì vậy, đệ quy được sử dụng ở đâu? Một ví dụ điển hình về thời điểm bạn muốn sử dụng đệ quy là tìm kiếm một cây nhị phân.
Khi dữ liệu được cấu trúc trong cây nhị phân, bạn phải đi xuống rất nhiều đường để tìm kiếm dữ liệu. Tại mỗi điểm trên cây, bạn phải quyết định xem bạn muốn tiếp tục tìm kiếm ở bên phải hay bên trái. Bạn có thể lưu phần nào của cây mà bạn đã truy cập trong một biến, nhưng một hàm đệ quy có thể theo dõi thông tin đó một cách tự nhiên.
Hãy tưởng tượng rằng chúng ta đang tìm kiếm số sáu trong cái cây ở trên. Chúng ta có thể tạo một hàm đệ quy tìm kiếm cây từ trái sang phải. Thuật toán sẽ trông giống như sau:
FUNCTION searchTree(branchToSearch) IF find 6 OR end of tree THEN RETURN result ELSE PROCESS branch CALL FUNCTION searchTree(left) CALL FUNCTION searchTree(right) END FUNCTION
Trong ví dụ về mã giả này, thuật toán sẽ tìm kiếm phía bên trái của cây trước tiên. Mỗi khi nó truy cập một số mới, chức năng sẽ bị tạm dừng và lưu trong bộ nhớ. Điều này cho phép chúng tôi theo dõi chúng tôi đã ở đâu.
Thuật toán sẽ luôn tìm kiếm phía bên trái càng xa càng tốt trước tiên. khi nó đến cuối cây, searchTree (trái) sẽ hoàn thành và nó sẽ kiểm tra phía bên phải. Khi cả hai bên được kiểm tra, tìm kiếm sao lưu một nhánh và tiếp tục kiểm tra bên phải.
Nếu các thuật toán tìm kiếm toàn bộ cây, nó sẽ thực hiện theo thứ tự:
2, 7, 2, 6, 5, 11, 5, 9 và 4
Xem liệu bạn có thể theo dõi bằng cách sử dụng mã giả ở trên hay không.
Đánh giá đệ quy
Đệ quy là một chủ đề nâng cao. Sẽ mất một thời gian để hiểu và thậm chí lâu hơn để viết mã nó thành thạo. Nó sẽ hữu ích nếu bạn xem qua các hàm đệ quy từng bước. Nó thậm chí có thể giúp xếp chồng các thẻ chỉ mục hoặc ghi chú sau nó khi bạn xem qua một hàm khi học cách biểu diễn từng lệnh gọi hàm.
Khi viết một hàm đệ quy, hãy bắt đầu bằng cách quyết định cách bạn muốn thoát khỏi hàm. Tiếp theo, xác định cách thiết lập vòng lặp của bạn. Xác định thông tin nào cần được gửi đến lệnh gọi chức năng tiếp theo và thông tin nào cần được trả lại.
Cách tốt nhất để học đệ quy là thực hành nó và học hỏi từ những sai lầm của bạn. Xem một số mã cũ của bạn và thử thách bản thân viết lại các vòng lặp dưới dạng hàm đệ quy. Nó có thể sẽ không làm cho mã của bạn hiệu quả hơn, nhưng nó sẽ là một phương pháp hay.