Big O: giới hạn trên
Cung điện lớn O O ( O ) đến nay là một phổ biến nhất. Khi bạn phân tích độ phức tạp của một thuật toán, hầu hết thời gian, điều quan trọng là có một số giới hạn trên về thời gian chạy nhanh như thế nào khi kích thước của đầu vào tăng lên. Về cơ bản, chúng tôi muốn biết rằng việc chạy thuật toán sẽ không mất nhiều thời gian. Chúng ta không thể biểu thị điều này theo đơn vị thời gian thực tế (giây), bởi vì điều đó phụ thuộc vào việc triển khai chính xác (cách viết chương trình, trình biên dịch tốt như thế nào, tốc độ của bộ xử lý của máy, tốc độ). Vì vậy, chúng tôi đánh giá những gì không phụ thuộc vào các chi tiết như vậy, đó là mất bao lâu để chạy thuật toán khi chúng tôi cung cấp cho đầu vào lớn hơn. Và chúng tôi chủ yếu quan tâm khi chúng tôi có thể chắc chắn rằng chương trình đã được thực hiện, vì vậy chúng tôi thường muốn biết rằng nó sẽ mất nhiều thời gian như vậy hoặc ít hơn.
Để nói rằng một thuật toán có thời gian chạy là cho kích thước đầu vào n có nghĩa là tồn tại một số K không đổi để thuật toán hoàn thành tối đa KO(f(n))nK các bước, tức là thời gian chạy của thuật toán tăng nhanh nhất là f (lên đến một hệ số tỷ lệ). Ghi nhận T ( n ) thời gian chạy của thuật toán cho kích thước đầu vào n , O ( n ) chính thức có nghĩa là T ( n ) ≤ f ( n ) lên đến một số yếu tố rộng.Kf(n)fT(n)nO(n)T(n)≤f(n)
Chặn dưới
Đôi khi, thật hữu ích khi có nhiều thông tin hơn giới hạn trên. là converse của O : nó biểu thị rằng một hàm phát triển ít nhất nhanh như hàm khác. T ( n ) = Ω ( g ( n ) ) có nghĩa là T ( N ) ≥ K ' g ( n ) đối với một số không đổi K ' , hoặc đặt nó không chính thức, T ( n ) ≥ g ( n ) lên đến một số nhân rộng hệ số.ΩOT(n)=Ω(g(n))T(N)≥K′g(n)K′T(n)≥g(n)
Khi thời gian chạy của thuật toán có thể được xác định chính xác, kết hợp O và Ω : nó biểu thị rằng tốc độ tăng trưởng của một hàm đã biết, cho đến một hệ số tỷ lệ. T ( n ) = Θ ( h ( n ) ) có nghĩa là K h ( n ) ≥ T ( n ) ≥ K ' h ( n ) đối với một số hằng số K và K ' . Nói một cách không chính thức, T (ΘOΩT(n)=Θ(h(n))Kh(n)≥T(n)≥K′h(n)KK′ lên đến một số yếu tố rộng.T(n)≈h(n)
Cân nhắc thêm
Các “nhỏ” và ω được sử dụng ít thường trong phân tích phức tạp. Ít o mạnh hơn O lớn ; Trong đó O chỉ ra sự tăng trưởng không nhanh hơn, o chỉ ra rằng sự tăng trưởng đó hoàn toàn chậm hơn. Ngược lại, ω cho thấy tốc độ tăng trưởng nhanh hơn đúng.oωoOOoω
Tôi đã hơi không chính thức trong các cuộc thảo luận ở trên. Wikipedia có định nghĩa formall và một cách tiếp cận toán học hơn.
Hãy nhớ rằng việc sử dụng dấu bằng trong và tương tự là một cách viết sai. Nói đúng ra, O ( f ( n ) ) là một tập hợp các hàm của biến n và chúng ta nên viết T ∈ O ( f ) .T(n)=O(f(n))O(f(n))nT∈O(f)
Ví dụ: một số thuật toán sắp xếp
Vì điều này khá khô khan, hãy để tôi đưa ra một ví dụ. Hầu hết các thuật toán sắp xếp có thời gian chạy trường hợp xấu nhất bậc hai, tức là đối với đầu vào có kích thước , thời gian chạy của thuật toán là O ( n 2 ) . Ví dụ, sắp xếp lựa chọn có thời gian chạy O ( n 2 ) , vì việc chọn phần tử thứ k yêu cầu so sánh n - k , với tổng số so sánh n ( n - 1 ) / 2 . Trong thực tế, số lượng so sánh luôn luôn chính xác n ( n -nO(n2)O(n2)kn−kn(n−1)/2 , phát triển thành n 2 . Vì vậy, chúng ta có thể chính xác hơn về độ phức tạp thời gian của sắp xếp lựa chọn: đó là Θ ( n 2 ) .n(n−1)/2n2Θ(n2)
Bây giờ hãy sắp xếp hợp nhất . Hợp nhất sắp xếp cũng là bậc hai ( ). Điều này đúng, nhưng không chính xác lắm. Hợp nhất sắp xếp trong thực tế có thời gian chạy O ( nO(n2) trong trường hợp xấu nhất. Giống như sắp xếp lựa chọn, luồng công việc của sắp xếp hợp nhất về cơ bản không phụ thuộc vào hình dạng của đầu vào và thời gian chạy của nó luôn là nO(nlg(n)) lên đến một yếu tố chất nhân không đổi, tức là nó là Θ ( nnlg(n) .Θ(nlg(n))
Tiếp theo, hãy xem xét quicksort . Quicksort phức tạp hơn. Nó chắc chắn là . Hơn nữa, trường hợp xấu nhất của quicksort là bậc hai: các trường hợp xấu nhất là Θ ( n 2 ) . Tuy nhiên, trường hợp tốt nhất của quicksort (khi đầu vào đã được sắp xếp) là tuyến tính: tốt nhất chúng ta có thể nói cho một ràng buộc thấp hơn để quicksort nói chung là Ω ( n ) . Tôi sẽ không lặp lại chứng tại đây, nhưng trung bình độ phức tạp của quicksort (tỷ lệ trung bình thực hiện trên tất cả các hoán vị có thể của đầu vào) là Θ ( nO(n2)Θ(n2)Ω(n) .Θ(nlg(n))
Có kết quả chung về sự phức tạp của các thuật toán sắp xếp trong các cài đặt chung. Giả sử rằng một thuật toán sắp xếp chỉ có thể so sánh hai yếu tố tại một thời điểm, với kết quả có hoặc không ( hoặc x > y ). Sau đó, rõ ràng là thời gian chạy của thuật toán sắp xếp luôn luôn là Ω ( n ) (trong đó n là số phần tử cần sắp xếp), bởi vì thuật toán phải so sánh mọi phần tử ít nhất một lần để biết nó sẽ phù hợp ở đâu. Giới hạn dưới này có thể được đáp ứng, ví dụ, nếu đầu vào đã được sắp xếp và thuật toán chỉ so sánh từng phần tử với phần tử tiếp theo và giữ chúng theo thứ tự (đó là n - 1x≤yx>yΩ(n)nn−1so sánh). Điều ít rõ ràng hơn là thời gian chạy tối đa nhất thiết phải là . Có thể thuật toán đôi khi sẽ tạo ra các phép so sánh ít hơn, nhưng phải có một số K không đổisao cho với bất kỳ kích thước đầu vào n nào , có ít nhất một đầu vào mà thuật toán tạo ra nhiều hơn so sánh so với K n l g ( n ) . Ý tưởng của bằng chứng là xây dựng cây quyết định của thuật toán, tức là tuân theo các quyết định mà thuật toán lấy từ kết quả của mỗi so sánh. Vì mỗi so sánh trả về kết quả có hoặc không, cây quyết định là cây nhị phân. Có n !Ω(nlg(n))KnKnlg(n)n!hoán vị có thể có của đầu vào và thuật toán cần phân biệt giữa tất cả chúng, vì vậy kích thước của cây quyết định là . Kể từ khi cây là một cây nhị phân, phải mất độ sâu Θ ( l g ( n ! ) ) = Θ ( nn! để phù hợp với tất cả các nút. Độ sâu là số lượng tối đa các quyết định rằng các thuật toán mất, vì vậy chạy các thuật toán liên quan đến ít nhất này nhiều so sánh: thời gian chạy tối đa là Ω ( nΘ(lg(n!))=Θ(nlg(n)) .Ω(nlg(n))
¹ Hoặc tiêu thụ tài nguyên khác như không gian bộ nhớ. Trong câu trả lời này, tôi chỉ xem xét thời gian chạy.