2015-08-25 13 views
17

Tôi phải phân tích vòng lặp này, trong số những thứ khác và xác định thời gian chạy của nó bằng ký hiệu Big-O.Phân tích Big-O cho vòng lặp

for (int i = 0; i < n; i += 4) 
    for (int j = 0; j < n; j++) 
     for (int k = 1; k < j*j; k *= 2)` 

Dưới đây là những gì tôi có cho đến nay:

for (int i = 0; i < n; i += 4) = n 

for (int j = 0; j < n; j++) = n 

for (int k = 1; k < j*j; k *= 2) = log^2 n 

Bây giờ vấn đề tôi sắp đến là thời gian chạy cuối cùng của vòng lặp. Đoán tốt nhất của tôi là O (n^2), tuy nhiên tôi không chắc chắn nếu điều này đúng. Có ai giúp được không?

Chỉnh sửa: xin lỗi về Oh -> O điều. sách giáo khoa của tôi sử dụng "Big-Oh"

+1

Vì bạn thực thi tất cả các vòng bên trong cho mỗi lần lặp của các vòng ngoài, nó sẽ là phép nhân đơn giản, tức là O (n * n * log (n)). (Tuy nhiên, không kiểm tra kết quả cá nhân của bạn). – Thomas

+2

Tôi nghĩ rằng vòng thứ ba không phải là 'log^2 n', mà là 'log n^2', là' O (log n) '. –

+0

@Thomas vì vậy bạn vẫn sẽ nhân lên như bình thường, mặc dù có chức năng đăng nhập? JuanLopes bạn nói đúng! cảm ơn. –

Trả lời

18

Lưu ý đầu tiên rằng vòng lặp ngoài độc lập với hai vòng còn lại - nó chỉ đơn giản là thêm một hệ số (n/4)*. Chúng tôi sẽ xem xét điều đó sau.

Bây giờ chúng ta hãy xem xét sự phức tạp của

for (int j = 0; j < n; j++) 
    for (int k = 1; k < j*j; k *= 2) 

Chúng tôi có tổng sau:

0 + log (1) + log (2 * 2) + ... + log (n * n)

Nó là tốt để lưu ý rằng log (n^2) = 2 * log (n). Vì vậy chúng tôi lại yếu tố tổng để:

2 * (0 + log (1) + log (2) + ... + đăng nhập (n))

Nó không phải là rất dễ dàng để phân tích số tiền này nhưng hãy xem this post. Sử dụng xấp xỉ của Sterling có thể là thuộc về O(n*log(n)). Do đó độ phức tạp tổng thể là O((n/4)*2*n*log(n))= O(n^2*log(n))

+0

Điều đó rất hữu ích, cảm ơn bạn. Tuy nhiên, tôi không phải là 100% trên tính toán cho vòng lặp bên ngoài. Bạn có phiền xây dựng một chút không? –

+0

@ SarahvdByl bạn có nghĩa là vòng lặp trên 'i'? Nó độc lập với các vòng lặp khác và thực thi nó tương đương với việc thực hiện các vòng lặp bên trong 'n/4' lần. –

+4

Không cần Stirling: log2 (1) + log2 (2) + ... + log2 (n) <= log2 (n) + log2 (n) + ... + log2 (n) = n * log2 (n). Điều này không chứng minh rằng giới hạn là chặt chẽ, nhưng để có được O (-) là đủ. – chi

4

Thời gian phức tạp của một vòng lặp được coi là O (n) nếu các biến vòng lặp được tăng/giảm đi một lượng không đổi (đó là c trong ví dụ dưới đây):

for (int i = 1; i <= n; i += c) { 
     // some O(1) expressions 
    } 

    for (int i = n; i > 0; i -= c) { 
     // some O(1) expressions 
    } 

Độ phức tạp về thời gian của vòng lặp lồng nhau bằng số lần câu lệnh trong cùng được thực thi. Ví dụ các vòng mẫu sau đây có O (n ²) thời gian phức tạp:

for (int i = 1; i <=n; i += c) { 
     for (int j = 1; j <=n; j += c) { 
      // some O(1) expressions 
     } 
    } 

    for (int i = n; i > 0; i += c) { 
     for (int j = i+1; j <=n; j += c) { 
      // some O(1) expressions 
    } 

Thời gian phức tạp của một vòng lặp được coi là O (logn) nếu các biến vòng lặp được chia/nhân với một lượng không đổi:

for (int i = 1; i <=n; i *= c) { 
     // some O(1) expressions 
    } 
    for (int i = n; i > 0; i /= c) { 
     // some O(1) expressions 
    } 

Bây giờ chúng ta có:

for (int i = 0; i < n; i += 4) <----- runs n times 
    for (int j = 0; j < n; j++) <----- for every i again runs n times 
     for (int k = 1; k < j*j; k *= 2)` <--- now for every j it runs logarithmic times. 

Vì vậy, độ phức tạp là O (n²logm) trong đó m là n² có thể được đơn giản hóa thành O (n²logn)n²logm = n²logn² = n² * 2logn ~ n²logn.

+0

Trong khi nó hoạt động ở đây, nhân phức tạp của "vòng lặp bên trong" với "vòng ngoài" là không chính xác. Xem xét: 'for (i = 1; i amit

+2

Trong ẩn dụ, nó tương tự như giải thích 2 + 2 + 2 = 6 vì có ** 3 ** 2 và ** 2 ** + 's, và 3 * 2 = 6. Điều này rõ ràng không thành công cho 3 + 3 + 3 = 6, kể từ lần nữa - chúng tôi có ** 3 ** 3 và ** 2 ** + 's. – amit

+0

@amit Cảm ơn bạn đã làm rõ. –

7
  • Về j, vòng lặp bên trong là O(log_2(j^2)) thời gian, nhưng sin log_2(j^2)=2log(j), nó thực sự là O(log(j)).
  • Đối với mỗi lần lặp của vòng lặp giữa, phải mất O (log (j)) thời gian (để làm vòng lặp bên trong ), vì vậy chúng ta cần phải tổng hợp:

    sum {log (j) | nhật ký j = 1, ..., n-1} (1) + nhật ký (2) + ... + nhật ký (n-1) = log ((n-1)!)

Và kể từ log((n-1)!) là trong O((n-1)log(n-1)) = O(nlogn), chúng tôi có thể kết thúc vòng giữa ở giữa có các hoạt động O(nlogn).

  • Lưu ý rằng cả hai vòng giữa và bên trong là độc lập của i, vì vậy để được tổng độ phức tạp, chúng tôi chỉ có thể nhân n/4 (số lặp đi lặp lại của vòng lặp bên ngoài) với độ phức tạp của vòng lặp giữa, và nhận được:

    O (n/4 * nlogn) = O (n^2logn)

Vì vậy, tổng độ phức tạp của mã này là O(n^2 * log(n))

+0

+1 Tôi thích tham chiếu đến 'O (n * log (n)) = O (n!)' Nổi tiếng. Một lưu ý - Tôi nghĩ tốt hơn là nên sử dụng các hoạt động thay vì thời gian, ví dụ: 'vòng lặp bên trong thực hiện các hoạt động O (log_2 (j^2)) ' –

+0

@IvayloStrandjev Cảm ơn phản hồi. Đã chỉnh sửa. – amit

Các vấn đề liên quan