Một số ngôn ngữ cung cấp tối ưu hóa cuộc gọi đuôi, số tiền sẽ vứt bỏ khung ngăn xếp trước đó trước khi tạo ngôn ngữ mới. Chỉ có thể khi cuộc gọi đệ quy là thao tác cuối cùng xảy ra [nếu không bạn cần khung ngăn xếp vì nó chỉ vào phần còn lại của các hoạt động]. Python không, tuy nhiên.
Bạn có hai tùy chọn:
- Nếu chức năng đệ quy nhưng đệ quy không được thực hiện với các cuộc gọi đuôi, thì thường thì việc chuyển đổi sang đệ quy đuôi bằng cách thêm các tham số vào chữ ký chức năng. .
- Nếu bạn muốn tránh làm những điều trên, bạn cũng có thể chuyển đổi mã thành kiểu lặp lại sử dụng rõ ràng để lưu trữ mọi thứ, vì kích thước của ngăn xếp của bạn sẽ không bị ràng buộc, trong khi ngăn xếp cuộc gọi thường khá nhỏ [đó là nguyên nhân gây ra giới hạn độ sâu đệ quy].
Lưu ý rằng cả hai điều này là khó khăn hơn khi bạn có, giả sử, ba chức năng gọi nhau là đệ quy. Nhưng ý tưởng tổng thể là đưa ra mã mới bảo tồn hành vi của mã cũ mà không sử dụng đệ quy và rõ ràng cách bạn làm điều đó sẽ khác nhau tùy thuộc vào mã bắt đầu, mặc dù các mẫu chung [được liên kết ở trên] vẫn giữ nguyên .
Trong trường hợp của bạn, mã đi vào một vòng lặp vô hạn hoặc không, tùy thuộc vào a
, vì vậy
a = 1
def func3[]:
while a == 1:
pass
func3[]
sẽ đủ.
Như một lưu ý phụ: Đối với một số thuật toán, ghi nhớ có thể làm giảm số lượng cuộc gọi. Nếu kết quả cho các đầu vào lớn cho một hàm luôn được tạo ra từ kết quả của các đầu vào nhỏ hơn, được tính toán nhiều lần ["các vấn đề phụ chồng chéo"], thì bạn có thể giữ bộ đệm toàn cầu của các giá trị được trả về và kiểm tra bộ đệm trước khi thực hiện các cuộc gọi mới. Mã ghi nhớ chung có thể được viết bằng Python bằng cách sử dụng các nhà trang trí.
Để tái phát hay không tái diễn, đó là câu hỏi. Chúng ta đều biết về niềm vui chúng ta có với các chức năng đệ quy. Nhưng nó cũng có bộ giảm thiểu riêng, một trong số đó sẽ được giải thích trong bài viết này để giúp bạn chọn một cách khôn ngoan.
Giả sử, chúng ta cần tạo một chức năng mà khi được gọi là cần in dữ liệu trong danh sách được liên kết.
Điều này có thể được thực hiện theo 2 cách:
- 1. với đệ quy
- 2. Không có đệ quy
1. với đệ quy:With Recursion:
``` def print_linkedlist[head]: if head is not None: print[head.data] print_linkedlist[head.next] ```
Cách tiếp cận đầu tiên cũng hoạt động nhưng nếu danh sách thực sự dài như khoảng 1000 yếu tố thì chương trình sẽ đạt độ sâu đệ quy và lỗi. Không quên rằng khi chiều dài danh sách tăng, kích thước ngăn xếp cũng tăng tuyến tính.
Độ sâu đệ quy là gì?
Trước khi chúng tôi đi trước, bạn nên biết rằng vấn đề này là đặc thù của Python. Có những ngôn ngữ mà chúng tôi không gặp phải vấn đề này nhưng điều đó sẽ không được thảo luận ở đây. & nbsp; chúng tôi biết rằng một hàm đệ quy tự gọi. Điều này có nghĩa là một hàm mới được gọi trong hàm gốc. Giả sử một danh sách được liên kết đếm từ 0 đến n bằng 1 bằng cách sử dụng mã đệ quy được đề cập ở trên.
Hàm đầu tiên nhìn vào dữ liệu của nút đầu trong danh sách và sau đó in nó. Nhưng chức năng đầu tiên đã kết thúc. Một hàm cũ không thể kết thúc cho đến khi tất cả các chức năng bên trong nó đã kết thúc. Nếu chúng tôi quan sát ngăn xếp cuộc gọi có danh sách các chức năng đang chạy: & nbsp;
# the first function waiting for # innermost functions to end print_linkedlist[] # the child function called # within the first function print_linkedlist[]
Ngăn xếp cuộc gọi tiếp tục tăng lên khi các chức năng cũ không bao giờ kết thúc vì chúng đang chờ đợi các chức năng con bên trong kết thúc. Cuối cùng, ngăn xếp cuộc gọi trông giống như:
# original Function print_linkedlist[] # first level function print_linkedlist[] # second level function print_linkedlist[] # third level function print_linkedlist[] …… …… …… # 1000 level function – Maximum # Recursion Depth Reached print_linkedlist[]
Và BAMMM !!!!! Độ sâu đệ quy tối đa !!BAMMM!!!!! MAXIMUM RECURSION DEPTH!!
Một độ sâu đệ quy tính số lượng các lớp hoạt động bên trong hàm đệ quy. Trong Python, giới hạn độ sâu đệ quy tối đa mặc định là 1000. Giới hạn giúp ngăn chặn tràn ngăn xếp do đệ quy vô hạn.recursive depth limit is 1000. The limit helps prevent stack overflow which is caused by infinite recursion.
Do đó, cách tiếp cận thứ hai như dưới đây tốt hơn vì kích thước ngăn xếp không đổi.
2. & nbsp; không có đệ quy/ lặp lại:
``` def print_linkedlist[node]: while node: print[node.data] node=node.next ```
Sự kết luận
Đệ quy là niềm vui khi sử dụng nhưng bạn nên hiểu khi nào và khi nào không sử dụng nó. Một số ngôn ngữ như Scala và Haskell hỗ trợ một tính năng thú vị được gọi là đệ quy cuộc gọi đuôi, điều này ngăn chặn vấn đề độ sâu đệ quy bằng cách kết thúc cuộc gọi chức năng trước đó khi một cuộc gọi mới được thực hiện. Nhưng Python không hỗ trợ tính năng này. Vì vậy, ít nhất là trong Python, thích cách tiếp cận lặp hơn nếu bạn nghĩ rằng chức năng có thể đạt đến giới hạn đệ quy.TAIL CALL RECURSION which prevents the problem of recursion depth by ending the previous function’s call when a new call is made. But Python doesn’t support this feature. So, at least in Python, prefer the iterative approach if you think the function may hit the recursion limit.