2013-08-14 52 views
5

Ở trường đại học của tôi, tôi được yêu cầu viết một chương trình JAVA cho chuỗi Fibonacci. Tôi đã sử dụng đệ quy để viết chương trình đó.Làm cách nào để kiểm tra xem đệ quy hoặc lặp lại có tốt nhất cho một chương trình cụ thể không?

Nhưng, giảng viên viên nói rằng bản ngã của tôi không hiệu quả và yêu cầu tôi phân tích. Ông nói thêm rằng theo quy ước, lặp lại là phù hợp trong chương trình đó hơn đệ quy.

Cách phân tích thuật toán của chúng tôi? Làm thế nào để kiểm tra không gian và thời gian phức tạp trong cả hai lần lặp lại và đệ quy? Ngay sau đó, tôi thấy rằng những điều này cũng quan trọng như CORRECTNESS OF A PROGRAM.

+0

Nếu bạn sử dụng ints hoặc longs bạn sẽ không đi xa hơn 60 hoặc 70 lần thu thập để nó không thực sự quan trọng. Và bạn cũng có thể lưu trữ kết quả bằng phương pháp đệ quy. – assylias

+0

Ngoài ra: [đệ quy-hoặc-looping?] (Http://stackoverflow.com/questions/13346424/recursion-or-looping?lq=1) – nawfal

Trả lời

5

Là một thumbrule:

  • Đệ quy là dễ hiểu đối với con người. Nhưng nó là ngăn xếp dựa trên và ngăn xếp luôn luôn là một nguồn tài nguyên hữu hạn.
  • Lặp lại là một tuần tự, đồng thời dễ dàng gỡ lỗi hơn. Nhưng đôi khi có thể dẫn đến khó hiểu các thuật toán có thể dễ dàng thực hiện thông qua đệ quy.

Vì vậy, bất cứ khi nào số bước được giới hạn ở một số có thể quản lý nhỏ, bạn có thể truy cập lại. Vì bạn sẽ tự tin ngăn xếp sẽ không bao giờ tràn và đồng thời mã đệ quy là compact and elegant.

Nếu bạn muốn khám phá thêm, những điều này có thể hữu ích. Recursion vs loopsRecursion or Iteration?

Sửa Như đã chỉ ra bởi @MrP, một số special recursions, có thể được tối ưu hóa bằng một số trình biên dịch.

+2

Cũng giống như một nhận xét: đệ quy không phải luôn luôn ngăn xếp dựa. Một số trình biên dịch sẽ tối ưu hóa đệ quy đuôi để nó thực sự trở thành một sự lặp lại. Nhưng ofcourse bạn không thể luôn luôn dựa vào điều này. – MrP

+0

@MrP đúng nhưng như bạn đã nói: a) "một số" trình biên dịch - không phải tất cả, và b) ngay cả một trình biên dịch hỗ trợ tối ưu đệ quy đuôi không thể thực hiện nó cho bất kỳ đệ quy. Nhận xét tốt! – alfasin

+0

Cảm ơn bạn. Tôi chỉ tìm thấy chuỗi cho 7 thuật ngữ đầu tiên. Vì vậy, tôi đã không tìm thấy nhiều sự khác biệt trong khó khăn của hai phương pháp. Nhưng nếu bạn muốn, bạn có thể giải thích cho tôi về quan điểm của bạn, rằng "mã đệ quy là nhỏ gọn và thanh lịch" –

2

Không có gì liên quan đến độ phức tạp của thuật toán: khi bạn sử dụng đệ quy - mỗi cuộc gọi tạo khung mới trên ngăn xếp - vì vậy nếu đệ quy quá sâu, bạn có thể chạy vào StackOverflow :)

Bằng cách sử dụng lặp - bạn đang chạy trong một vòng lặp (có khả năng) trên cùng một không gian (ghi đè các tham số trước đó) nhanh hơn cũng như an toàn hơn từ phối cảnh StackOverflow.

2

Tôi khuyên bạn nên theo liên kết http://nptel.iitm.ac.in/courses.php?disciplineId=106 và tìm một số bài giảng về Thiết kế và phân tích thuật toán. Khái niệm cơ bản của nó về thiết kế các thuật toán. Chúc may mắn.

1

Vấn đề lớn nhất với dòng mã là thời gian phức tạp của thuật toán, khi bạn sử dụng đệ quy đơn giản, bạn sẽ tính toán lại mọi thứ và thực hiện nhiều công việc gấp đôi. Điều này là do khi bạn tính toán fib (n) bằng cách sử dụng

int fib(int n) { 
    if (n < 2) { return 1; } 
    return fib(n-1) + fib(n-2) 
} 

bạn sẽ tính toán fib (n-1), tính toán fib (n-2) và fib (n-3). Nhưng để tính toán fib (n), bạn sẽ tính toán fib (n-2). Để cải thiện điều này, bạn sẽ cần phải lưu trữ các kết quả tạm thời. Điều này thường dễ dàng hơn khi sử dụng lặp lại và bắt đầu từ i = 0 lên đến n. Bằng cách này bạn có thể dễ dàng lưu trữ hai kết quả cuối cùng và tránh tính toán cùng một giá trị hơn và hơn.

Cách dễ dàng để xem thuật toán có hiệu quả hay không là thử và giải quyết nó cho một vài ví dụ ngày càng khó hơn. Bạn cũng có thể tính toán chính xác hơn. Lấy ví dụ về mã vạch ở trên. Gọi fib (n) sẽ có sự phức tạp O(fib(n)) = O(fib(n-1)) +O(fib(n-2)) + 1 (chúng ta hãy lấy 1 để bổ sung).Giả sử rằng O(fib(0)) = O(fib(1)) = 1. Điều này có nghĩa là O(fib(2)) = 3, O(fib((3)) = 5, O(fib(4)) = 9. Như bạn có thể thấy, loạt bài này sẽ đi nhanh hơn so với dòng mã nguồn gốc chính nó! Điều này có nghĩa là một lượng lớn sự phức tạp ngày càng tăng. Khi bạn sẽ có một thuật toán lặp với vòng lặp for từ 0 đến n, độ phức tạp của bạn sẽ tăng theo thứ tự của n, điều này sẽ tốt hơn.

Để biết thêm thông tin, hãy kiểm tra ký hiệu lớn-o.

+0

Vâng. Cảm ơn bạn, bạn có thể đề nghị bất kỳ liên kết hoặc ref để đọc về ký hiệu o lớn? –

+0

Tôi đã tìm thấy bài viết trên wiki. Tôi có thể biết bất kỳ nguồn nào cho công nghệ phân tích và thiết kế thuật toán không? –

+1

Hướng dẫn Thiết kế Thuật toán của Steven S. Skiena khá tốt cũng như Giới thiệu các Thuật toán của Thomas H. Cormen. Chúng chứa thông tin về các vấn đề thiết kế và hiệu năng thuật toán tốt. – MrP