Xác định nếu một thuật toán là O (log n)


25

Tôi đang làm mới Lý thuyết CS của mình và tôi muốn biết cách xác định độ phức tạp của thuật toán O (log n). Cụ thể, có một cách dễ dàng để xác định nó?

Tôi biết với O (n), bạn thường có một vòng lặp duy nhất; O (n ^ 2) là một vòng lặp kép; O (n ^ 3) là một vòng lặp ba, v.v ... Còn O (log n) thì sao?



À, đó là nơi tôi không nhìn thấy :)
Atif

Câu trả lời:


32

Tôi biết với O (n), bạn thường có một vòng lặp duy nhất; O (n ^ 2) là một vòng lặp kép; O (n ^ 3) là một vòng lặp ba, v.v ... Còn O (log n) thì sao?

Bạn đang thực sự đi về nó sai cách ở đây. Bạn đang cố gắng ghi nhớ biểu thức big-O nào đi với cấu trúc thuật toán nhất định, nhưng bạn thực sự chỉ nên đếm số lượng thao tác mà thuật toán yêu cầu và so sánh với kích thước của đầu vào. Một thuật toán lặp trên toàn bộ đầu vào của nó có hiệu suất O (n) vì nó chạy vòng lặp n lần, không phải vì nó có một vòng lặp. Đây là một vòng lặp duy nhất với hiệu suất O (log n):

for (i = 0; i < log2(input.count); i++) {
    doSomething(...);
}

Vì vậy, bất kỳ thuật toán nào có số lượng thao tác cần thiết theo thứ tự logarit của kích thước của đầu vào là O (log n). Điều quan trọng mà phân tích big-O nói với bạn là thời gian thực hiện của thuật toán thay đổi như thế nào so với kích thước của đầu vào: nếu bạn tăng gấp đôi kích thước của đầu vào, thuật toán có thực hiện thêm 1 bước nữa không (O (log n)) , gấp đôi số bước (O (n)), gấp bốn lần số bước (O (n ^ 2)), v.v.

Liệu có giúp biết được từ kinh nghiệm rằng các thuật toán liên tục phân vùng đầu vào của chúng thường có 'log n' là một thành phần của hiệu suất của chúng không? Chắc chắn rồi. Nhưng đừng tìm phân vùng và đi đến kết luận rằng hiệu suất của thuật toán là O (log n) - nó có thể giống như O (n log n), khá khác biệt.


3
Lưu ý rằng một cách thông tục hơn để nói "theo thứ tự logarit của kích thước" là nói "theo thứ tự số lượng chữ số trong kích thước".

@Caleb cơ sở thực tế của logarit là không quan trọng khi nói tỷ lệ.

@Caleb nói chuyện tuyệt đối không có ý nghĩa với big-O. Một từ mà bạn có thể thích hơn: khi số chữ số tăng gấp đôi, số bước tăng gấp đôi.

@Caleb nói chuyện tuyệt đối không có ý nghĩa với big-O. Một từ mà bạn có thể thích hơn: khi số chữ số tăng gấp đôi, số bước tăng gấp đôi.

@ ThorbjørnRavnAndersen Vâng, đó là "logarit của kích thước" nghĩa là gì. Tôi không chắc vấn đề của bạn với cụm từ đó là gì, ngoại trừ việc bạn đã chọn nói khác đi. Về cơ bản, tôi nghĩ rằng chúng tôi đồng ý.
Caleb

25

Ý tưởng là một thuật toán là O(log n)nếu thay vì cuộn qua cấu trúc 1, 1, bạn chia cấu trúc này nhiều lần và thực hiện một số lượng hoạt động không đổi cho mỗi lần phân chia. Các thuật toán tìm kiếm trong đó không gian câu trả lời tiếp tục được phân chia O(log n). Một ví dụ về điều này là tìm kiếm nhị phân , trong đó bạn tiếp tục chia một mảng theo thứ tự lặp đi lặp lại cho đến khi bạn tìm thấy số.

Lưu ý: Bạn không nhất thiết phải chia thành hai nửa chẵn.


1
Điều gì sẽ xảy ra nếu tôi chia đầu vào thành hai lần và sau đó lặp lại 2 ^ (n / 2) lần còn lại trước khi chia lại lần nữa? (Tất nhiên tôi biết những gì sau đó, tôi chỉ muốn đưa ra một ví dụ trong đó phương pháp đơn giản này thất bại).
Tamás Szelei

@afish Đó là loại hiếm. Thật là hiếm khi tìm kiếm.
Donal Fellows

1
@DonalFellows Lý thuyết thuật toán không phải là một khoa học thực nghiệm. Và câu hỏi không phải là về tìm kiếm, chỉ là việc đề cập đến log nphản xạ tìm kiếm nhị phân được kích hoạt ở mọi người.
Tamás Szelei

2
Phân vùng không tạo ra thuật toán O (log n), nó (thường) thêm một yếu tố của log n vào giới hạn big-O. Các loại đệ quy như heapsort và mergesort là những ví dụ hoàn hảo: chúng phân vùng đầu vào, nhưng sau đó chúng phân vùng đệ quy cả hai phân vùng kết quả. Kết quả là hiệu suất O (n log n).
Caleb

@afish: Điểm tốt. Mục tiêu của tôi với câu trả lời này là giữ cho nó đơn giản nhất có thể với bản chất của câu hỏi. Tôi đã thay đổi dòng "bạn chia cấu trúc thành một nửa ..." thành "bạn chia cấu trúc thành một nửa ... và thực hiện một số lượng hoạt động không đổi cho mỗi lần phân tách" để cố gắng hiểu điểm này một cách đơn giản.
Casey Patton

2

Các ví dụ điển hình là những người liên quan đến tìm kiếm nhị phân. Ví dụ, một thuật toán tìm kiếm nhị phân thường là O(log n).

Nếu bạn có một cây tìm kiếm nhị phân , việc tra cứu, chèn và xóa đều O(log n)phức tạp.

Bất kỳ tình huống nào bạn liên tục phân vùng không gian thường sẽ liên quan đến một log nthành phần. Đây là lý do tại sao nhiều thuật toán sắp xếp có O(nlog n)độ phức tạp, bởi vì chúng thường phân vùng một tập hợp và sắp xếp khi chúng đi.


1

Nếu bạn muốn nó đơn giản như "vòng lặp đơn -> O (n), vòng lặp kép -> O (n ^ 2)", thì câu trả lời có lẽ là "Cây -> O (log n)". Chính xác hơn là đi ngang qua một cây từ gốc đến một lá (không phải tất cả!) Hoặc ngược lại. Tuy nhiên, đây là tất cả các đơn giản hóa.


Vì vậy, điều gì là sai với câu trả lời của tôi? Tôi cởi mở với những lời chỉ trích mang tính xây dựng.
Scarfridge

0

Bạn muốn biết liệu có một cách dễ dàng để xác định nếu một thuật toán là O (log N).

Vâng: chỉ cần chạy và thời gian nó. Chạy nó cho đầu vào 1.000, 10.000, 100.000 và một triệu.

Nếu bạn thấy thời gian chạy là 3,4,5,6 giây (hoặc một số bội số), bạn có thể nói đó là O (log N) một cách an toàn. Nếu giống như: 1,10,100,1000 giây thì có lẽ là O (N). Và nếu nó giống như 3,40.500,6000 giây thì đó là O (N log N).


Mọi người nên đưa ra câu trả lời này một upvote và một downvote, cả hai vì những lý do rõ ràng :-)
gnasher729
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.