Tất cả các hàm đệ quy có thể được mã hóa bằng các lần lặp không? [đóng cửa]


10

Những lợi thế của đệ quy là gì?

Một số ngôn ngữ lập trình có thể tối ưu hóa đệ quy đuôi, nhưng, nói chung, đệ quy tiêu tốn nhiều tài nguyên hơn các vòng lặp thông thường.

Có thể có một phiên bản lặp của một số hàm đệ quy không?



Câu trả lời:


10

Có, bạn có thể mã các hàm đệ quy dưới dạng lặp. Về cơ bản, nó yêu cầu bạn duy trì thông tin theo cách thủ công mà nếu không thì sẽ được chăm sóc bởi mã gọi phương thức do trình biên dịch tạo ra.

Nói cách khác, bạn cần một ngăn xếp trong đó mỗi mục nhập là một cấu trúc chứa các tham số đã truyền và tất cả các biến cục bộ. Bạn luôn làm việc trên mục nhập cao nhất trên ngăn xếp. Nếu bạn cần gọi cho mình, hãy tạo một mục mới và đặt lên trên cùng của ngăn xếp. Khi hoàn tất, hãy nhập mục trên cùng của ngăn xếp để hiển thị mục bên dưới và sử dụng mục nhập trên cùng trước đó để trích xuất các giá trị trả về và cập nhật mục nhập trên cùng mới tương ứng.

Tôi đề nghị bạn nghiên cứu một cuốn sách biên dịch để xem cách thức này thường được thực hiện trong mã máy.


Tôi hiểu rồi. Vì vậy, lợi thế nào sẽ đệ quy có? Sự đơn giản?
OscarRyz

2
@OscarRyz: Vâng, và nó thanh lịch hơn.
Michael K

@OscarRyz, cách tôi mô tả đệ quy. Nó chỉ không được thực hiện với các hướng dẫn CPU gốc. Làm thủ công cho phép bạn thực hiện mọi việc - như song song hóa - ánh xạ xấu đến các hướng dẫn gốc.

15

Đệ quy thường là một cách tự nhiên hơn để nhìn vào mọi thứ hơn là lặp đi lặp lại. Ví dụ, hãy xem xét inorder traversal của cây nhị phân: inorder(left); process(); inorder(right);đơn giản hơn nhiều so với việc duy trì rõ ràng một ngăn xếp.

Miễn là bạn không đi quá sâu (thổi chồng), sự khác biệt trong sử dụng tài nguyên thường là không đáng kể. Đừng lo lắng về nó nói chung. Mã đơn giản thường tốt hơn mã được tối ưu hóa bằng tay, mặc dù vẫn có trường hợp ngoại lệ. Đúng là bình thường tốt hơn nhanh.

Bất kỳ thuật toán đệ quy nào cũng có thể được biểu diễn dưới dạng thuật toán lặp, nhưng bạn có thể cần giữ một ngăn xếp rõ ràng (tương ứng với ngăn xếp cuộc gọi được xử lý ngầm). Rốt cuộc, nếu bạn biên dịch một hàm đệ quy, bạn sẽ có được thứ gì đó dựa vào thao tác một ngăn xếp và lặp qua hàm đó, và đó là phép lặp.

Các hàm đệ quy đuôi có thể dễ dàng dịch thành các vòng lặp và không cần ngăn xếp, nhưng đó là trường hợp đặc biệt.


8
Tôi muốn nói rằng quyền luôn luôn tốt hơn nhanh. Mã làm điều sai rất nhanh không tốt cho bất kỳ ai.
Mason Wheeler

1
Nhưng nếu bạn có thể làm điều sai đó thật nhanh thì sao?!
RationalGeek

1
@jkohlhepp - Tôi có thể giải quyết mọi vấn đề ngay lập tức. Câu trả lời là 0.
Lưu ý đến bản thân - nghĩ về một cái tên

2
Sử dụng đệ quy thay vì ngăn xếp rõ ràng có thể hiệu quả hơn - tránh sự cần thiết phải phân bổ heap, phân mảnh bộ nhớ có thể và các vấn đề cục bộ có thể. Tuy nhiên, trên "bên phải thường tốt hơn nhanh", tràn ngăn xếp trong trường hợp phần mềm của bạn cần xử lý có nghĩa là mã của bạn bị hỏng. Thông thường, các trường hợp vấn đề khá dễ phát hiện - đệ quy trên cây cân bằng (hợp lý) là tốt, nhưng đệ quy trên cây có thể rất mất cân bằng hoặc trong danh sách được liên kết, có thể là một lỗi nghiêm trọng trong ngôn ngữ như C. Worse , nó có thể tồn tại trong thử nghiệm đơn giản và chỉ bị sập khi được triển khai thực sự.
Steve314

1
Tôi nghĩ tất cả các bạn đều hiểu ý của Mason và chỉ đang pha trò vì sự thú vị của nó. Tất nhiên một chương trình đúng chậm sẽ hữu ích hơn một chương trình nhanh không chính xác.
Giorgio

4

Những lợi thế của đệ quy là gì?

Hãy thử giải quyết vấn đề Tháp Hà Nội lặp đi lặp lại. Một khi bạn từ bỏ, hãy xem giải pháp lặp và so sánh nó với giải pháp đệ quy. Cái nào đơn giản hơn?

Có thể có một phiên bản lặp của một số hàm đệ quy không?

Vâng, về nguyên tắc. Tuy nhiên, đối với nhiều vấn đề, bao gồm các tác vụ rất phổ biến, chẳng hạn như duyệt qua cây, các giải pháp đệ quy đơn giản và thanh lịch hơn nhiều so với các tác vụ lặp.


3

Những lợi thế của đệ quy là gì?

Sự đơn giản. Nếu không tối ưu hóa cuộc gọi đuôi, tất nhiên sẽ tốn nhiều tài nguyên hơn (stack), nhưng bạn sẽ triển khai như thế nào deltreetrong Java mà không cần đệ quy? Vấn đề là chỉ delete()có thể xóa các thư mục nếu chúng trống; Đây là đệ quy:

deltree(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory()) {
        for (File subFileOrDirectory : fileOrDirectory.listFiles()) {
            deltree(subFileOrDirectory);
        }
    }
    fileOrDirectory.delete();
}

1
Với một ngăn xếp, như được đề cập bởi các câu trả lời khác.
Nicole

Vâng, nhưng nó đơn giản đến mức nào? -)
Joonas Pulakka

Oh, đệ quy chắc chắn là tốt hơn. Tôi nghĩ bạn đã nói rằng điều đó là không thể.
Nicole

0

Tôi tin rằng đệ quy là một trong những công cụ mà một lập trình viên phải sống. Với đệ quy, bạn có thể "nghĩ" các thuật toán của mình và giải quyết chúng theo cách bạn nghĩ về nó. Nhưng, tôi phải cảnh báo bạn, mọi người đang nói về sự đệ quy đẹp như thế nào và mức độ đơn giản mang lại cho mã, liên quan đến việc tôi có một vài điều để nói:

  1. Trước hết, suy nghĩ "cách đệ quy" của một thuật toán là không dễ dàng. Xây dựng một chức năng như một nhân tố (n!) Hoặc một cái gì đó giống như Tháp Hà Nội chỉ là phần nổi của tảng băng trôi, và để chạm đáy đòi hỏi một thời gian ngắn.
  2. Đừng nghĩ rằng đệ quy chỉ mang lại sự đơn giản cho mã của bạn, đôi khi, cách lặp lại là xấu xí và lộn xộn, nhưng hiệu quả về chi phí (xem xét giải pháp đệ quy của vấn đề Fibonacci)

Có những điều đó trong tâm trí, học đệ quy! thật buồn cười, phức tạp và nó sẽ đập nát não bạn!, nhưng bạn sẽ thấy mình yêu nó.

May mắn nhất!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.