Có thể coi giá trị nhỏ của n, O (n) như thể O (1)


26

Tôi đã nghe nhiều lần rằng với các giá trị đủ nhỏ của n, O (n) có thể được nghĩ về / được xử lý như thể đó là O (1).

Ví dụ :

Động lực để làm như vậy dựa trên ý tưởng không chính xác rằng O (1) luôn tốt hơn O (lg n), luôn tốt hơn O (n). Thứ tự tiệm cận của một hoạt động chỉ có liên quan nếu trong điều kiện thực tế, kích thước của vấn đề thực sự trở nên lớn. Nếu n vẫn nhỏ thì mọi vấn đề là O (1)!

Thế nào là đủ nhỏ? 10? 100? 1.000? Tại thời điểm nào bạn nói "chúng ta không thể coi điều này như một hoạt động miễn phí nữa"? Có một quy tắc của ngón tay cái?

Điều này có vẻ như có thể là miền hoặc trường hợp cụ thể, nhưng có bất kỳ quy tắc chung nào về cách nghĩ về điều này không?


4
Nguyên tắc phụ thuộc vào vấn đề bạn muốn giải quyết. Có nhanh trên các hệ thống nhúng với không? Xuất bản trong lý thuyết phức tạp? n100
Raphael

3
Nghĩ về nó nhiều hơn, về cơ bản cảm thấy không thể đưa ra một quy tắc duy nhất, bởi vì các yêu cầu về hiệu suất được xác định bởi tên miền của bạn và các yêu cầu kinh doanh của nó. Trong các môi trường không bị hạn chế tài nguyên, n có thể khá lớn. Trong môi trường bị hạn chế nghiêm trọng, nó có thể khá nhỏ. Điều đó dường như rõ ràng bây giờ trong nhận thức muộn màng.
rianjs

12
@rianjs Bạn dường như được nhầm O(1)cho miễn phí . Lý do đằng sau một vài câu đầu tiên O(1)không đổi , đôi khi có thể rất chậm. Một phép tính mất một nghìn tỷ năm bất kể đầu vào là một O(1)phép tính.
Vịt Mooing

1
Câu hỏi liên quan về lý do tại sao chúng tôi sử dụng tiệm cận ở nơi đầu tiên.
Raphael

3
@rianjs: lưu ý các câu chuyện cười dọc theo dòng chữ "một hình ngũ giác xấp xỉ một hình tròn, cho các giá trị đủ lớn là 5". Câu bạn đang hỏi về việc đưa ra một quan điểm, nhưng vì nó gây ra cho bạn một số nhầm lẫn, có thể đáng để bạn hỏi Eric Lippert ở mức độ nào sự lựa chọn chính xác của cụm từ này là có hiệu quả hài hước. Anh ta có thể nói, "nếu có bất kỳ giới hạn trên nào trên thì mọi vấn đề đều là " và vẫn đúng về mặt toán học. "Nhỏ" không phải là một phần của toán học. O ( 1 )nO(1)
Steve Jessop

Câu trả lời:


21

Tất cả các đơn đặt hàng cường độ liên quan đến một hằng số , một vài trong số chúng thực sự. Khi số lượng vật phẩm đủ lớn mà hằng số không liên quan. Câu hỏi là liệu số lượng vật phẩm có đủ nhỏ để hằng số đó chiếm ưu thế hay không.C

Đây là một cách trực quan để suy nghĩ về nó.

nhập mô tả hình ảnh ở đây

Tất cả đều có hằng số khởi động xác định điểm bắt đầu của chúng trên trục Y. Mỗi cái cũng có hằng số quan trọng chi phối mức độ chúng sẽ tăng nhanh.C

  • Với , C xác định thời gian.O(1)C
  • thực sự là C × n , trong đó C xác định góc.O(n)C×nC
  • thực sự là ( C × n ) 2 , trong đó C xác định độ sắc nét của đường cong.O(n2)(C×n)2C

Để xác định thuật toán nào bạn nên sử dụng, bạn cần ước tính vị trí nơi thời gian chạy giao nhau. Ví dụ: giải pháp có thời gian khởi động cao hoặc C cao sẽ thua giải pháp O ( n ) với thời gian khởi động thấp và C thấp với số lượng mặt hàng khá lớn.O(1)CO(n)C

Đây là một ví dụ thực tế. Bạn phải di chuyển một đống gạch trên sân. Bạn có thể di chuyển chúng vài lần một lúc bằng tay hoặc đi lấy một chiếc máy xúc đào lớn, chậm để nâng và lái chúng trong một chuyến đi. Câu trả lời của bạn là gì nếu có ba viên gạch? Câu trả lời của bạn là gì nếu có ba ngàn?

Đây là một ví dụ CS. Giả sử bạn cần một danh sách luôn được sắp xếp. Bạn có thể sử dụng một cây sẽ giữ chính nó cho . Hoặc bạn có thể sử dụng danh sách chưa sắp xếp và sắp xếp lại sau mỗi lần chèn hoặc xóa tại O ( n log n ) . Bởi vì các hoạt động của cây rất phức tạp (chúng có hằng số cao) và việc sắp xếp rất đơn giản (hằng số thấp), danh sách có thể sẽ giành được tới hàng trăm hoặc hàng ngàn mặt hàng.O(logn)O(nlogn)

Bạn có thể cầu mắt loại này, nhưng cuối cùng điểm chuẩn là những gì sẽ làm điều đó. Bạn cũng phải để ý xem bạn sẽ có bao nhiêu vật phẩm và giảm thiểu rủi ro khi được trao nhiều hơn. Bạn cũng sẽ muốn ghi lại giả định của mình như "hiệu suất sẽ giảm nhanh chóng trên các mục " hoặc "chúng tôi giả sử kích thước được đặt tối đa là X ".XX

Vì các yêu cầu này có thể thay đổi, điều quan trọng là đặt các loại quyết định này đằng sau một giao diện. Trong ví dụ về cây / danh sách ở trên, không để lộ cây hoặc danh sách. Bằng cách đó, nếu các giả định của bạn hóa ra là sai hoặc bạn tìm thấy một thuật toán tốt hơn, bạn có thể thay đổi suy nghĩ của mình. Bạn thậm chí có thể thực hiện một thuật toán lai và chuyển đổi linh hoạt khi số lượng vật phẩm tăng lên.


Thật vô nghĩa khi nói . Những gì bạn thực sự có ý nghĩa là nếu thời gian chạy là T = O ( 1 ) sau đó (trong nhiều trường hợp) T C . Nếu T = O ( n ) thì trong nhiều trường hợp T C n , hoặc chính thức hơn T = C n + o ( n ) . Và như vậy. Tuy nhiên, lưu ý rằng trong các trường hợp khác, hằng số C thay đổi theoO(1)=O(C)T=O(1)TCT=O(n)TCnT=Cn+o(n)C , trong giới hạn nhất định. n
Yuval Filmus

@YuvalFilmus Đây là lý do tại sao tôi thích đồ thị.
Schwern

Đây là câu trả lời tốt nhất cho đến nay, vấn đề là chức năng phát triển nhanh như thế nào.
Ricardo

1
Đồ thị đẹp, nhưng trục thực sự nên được dán nhãn "thời gian", không phải "tốc độ". y
Ilmari Karonen

1
Là dòng thực sự là một parabola không? Nó trông rất phẳng cho n nhỏ và rất dốc cho n lớn . Ôi(n2)nn
David Richerby

44

Điều này phần lớn là ủng hộ những câu trả lời đã được đăng, nhưng có thể đưa ra một quan điểm khác.

Nó tiết lộ rằng câu hỏi thảo luận về "giá trị đủ nhỏ của n ". Toàn bộ quan điểm của Big-O là mô tả cách xử lý phát triển như một chức năng của những gì đang được xử lý. Nếu dữ liệu đang được xử lý ở mức nhỏ, việc thảo luận về Big-O là không liên quan, vì bạn không quan tâm đến sự tăng trưởng (điều này không xảy ra).

Nói cách khác, nếu bạn đi một quãng đường rất ngắn xuống phố, có thể đi bộ, sử dụng xe đạp hoặc lái xe cũng nhanh không kém. Nó thậm chí có thể nhanh hơn để đi bộ nếu phải mất một thời gian để tìm chìa khóa xe của bạn, hoặc nếu xe của bạn cần xăng, vv

Đối với n nhỏ , sử dụng bất cứ điều gì thuận tiện.

Nếu bạn đang thực hiện một chuyến đi xuyên quốc gia, thì bạn cần xem xét các cách để tối ưu hóa việc lái xe, tiết kiệm xăng, v.v.


5
"Đối với n nhỏ, sử dụng bất cứ điều gì thuận tiện." - nếu bạn thực hiện thao tác thường xuyên , hãy chọn nhanh nhất (cho của bạn ). Xem thêm tại đây . n
Raphael

4
Ẩn dụ tuyệt vời!
Evorlor

1
Từ quan điểm toán học thuần túy, sự phức tạp tiệm cận cho bạn biết không có gì khi n < infinity.
Gordon Gustafson

15

Câu nói khá mơ hồ và thiếu chính xác. Có ít nhất ba cách liên quan để giải thích nó.

Điểm toán học theo nghĩa đen đằng sau đó là, nếu bạn chỉ quan tâm đến các trường hợp kích thước lên đến một giới hạn nào đó thì chỉ có rất nhiều trường hợp có thể xảy ra. Ví dụ, chỉ có nhiều đồ thị hữu hạn trên một trăm đỉnh. Nếu chỉ có một số lượng các trường hợp hữu hạn, về nguyên tắc, bạn có thể giải quyết vấn đề bằng cách chỉ cần xây dựng một bảng tra cứu tất cả các câu trả lời cho tất cả các trường hợp có thể. Bây giờ, bạn có thể tìm thấy câu trả lời bằng cách kiểm tra đầu tiên rằng đầu vào không quá lớn (mất thời gian không đổi: nếu đầu vào dài hơn  k, không hợp lệ) và sau đó tra cứu câu trả lời trong bảng (mất thời gian không đổi: có một số mục cố định trong bảng). Tuy nhiên, lưu ý rằng kích thước thực tế của bảng có thể rất lớn. Tôi đã nói rằng chỉ có một số lượng đồ thị hữu hạn trên một trăm đỉnh và đó là sự thật. Chỉ là số lượng hữu hạn lớn hơn số lượng nguyên tử trong vũ trụ quan sát được.

Một điểm thực tế hơn là, khi chúng ta nói rằng thời gian chạy của một thuật toán là , mà chỉ có nghĩa rằng đó là tiệm c n 2  bước, đối với một số không đổi  C . Đó là, có một số liên tục n 0 như vậy mà, cho tất cả n n 0 , thuật toán mất khoảng c n 2 bước. Nhưng có thể n 0 = 100 , 000 , 000Θ(n2) cn2Cn0nn0cn2n0=100,000,000và bạn chỉ quan tâm đến các trường hợp kích thước nhỏ hơn thế nhiều. Giới hạn bậc hai không triệu chứng có thể thậm chí không áp dụng cho các trường hợp nhỏ của bạn. Bạn có thể may mắn và nó có thể nhanh hơn với các đầu vào nhỏ (hoặc bạn có thể không may mắn và làm cho nó chậm hơn). Ví dụ: đối với nhỏ  , n 2 < 1000 n, vì vậy bạn muốn chạy thuật toán bậc hai với hằng số tốt hơn thuật toán tuyến tính với hằng số xấu. Một ví dụ thực tế của điều này là các thuật toán nhân ma trận hiệu quả nhất (các biến thể của Coppersmith Trực Win giác , chạy trong thời gian O ( n 2.3729 ) ) hiếm khi được sử dụng trong thực tế vì O của Strassennn2<1000nO(n2.3729) Thuật toán ( n 2.8074 ) nhanh hơn trừ khi ma trận của bạn thực sự lớn.O(n2.8074)

Điểm thứ ba là, nếu  nhỏ, n 2 và thậm chí n 3  nhỏ. Ví dụ, nếu bạn cần phải sắp xếp một vài ngàn mục dữ liệu và bạn chỉ cần sắp xếp chúng một lần, bất kỳ thuật toán sắp xếp là đủ tốt: a Θ ( n 2 )nn2n3Θ(n2)thuật toán vẫn chỉ cần vài chục triệu hướng dẫn để sắp xếp dữ liệu của bạn, điều này hoàn toàn không mất nhiều thời gian trên CPU có thể thực hiện hàng tỷ hướng dẫn mỗi giây. OK, cũng có truy cập bộ nhớ, nhưng ngay cả một thuật toán chậm sẽ mất ít hơn một giây, vì vậy có lẽ tốt hơn là sử dụng thuật toán đơn giản, chậm và làm cho đúng hơn là sử dụng thuật toán phức tạp, nhanh và thấy rằng nó nhanh như chớp nhưng lỗi và không thực sự sắp xếp dữ liệu đúng.


4
Trong khi điểm hoàn toàn chính xác và hợp lệ, tôi nghĩ rằng bạn đã bỏ lỡ điểm. Có vẻ như họ có nghĩa là đôi khi thuật toán với tốt hơn thuật toán với O ( 1 ) , với n n đủ nhỏ . Điều này xảy ra, ví dụ, khi cái trước có thời gian chạy 10 n + 50 , trong khi cái sau chạy ở thời điểm 100000 . Sau đó, với n đủ nhỏ, nó thực sự nhanh hơn để sử dụng giao thức O ( n ) . O(n)O(1)n10n+50100000nO(n)
Ran G.

@RanG. Không phải đó là trường hợp thứ hai của tôi? (Đặc biệt là nếu tôi chỉnh sửa nó để nói điều gì đó giống như "Một tuyến tính thuật toán với các hằng số tốt có thể đánh bại một hằng số / thuật toán logarit với các hằng số xấu"?)
David Richerby

1
Sẽ là tốt để đề cập rõ ràng tầm quan trọng của các hằng số khi n nhỏ. Đó là điều mà có lẽ sẽ không xảy ra với những người chưa từng nghe nó trước đây.
Rob Watts

9

Ký hiệu Big-O thực sự chỉ nói điều gì đó về hành vi cho n lớn tùy ý. Ví dụ: có nghĩa là có hằng số c> 0 và số nguyên n 0 sao cho f ( n ) < c n 2 với mọi n > n 0 .f(n)=O(n2)n0f(n)<cn2n>n0

Trong nhiều trường hợp, bạn có thể tìm thấy một hằng số c và nói "Với mọi n> 0, f (n) xấp xỉ ". Đó là thông tin hữu ích để có. Nhưng trong một số trường hợp, điều này không đúng. Nếu f (n) = n 2 + 10 18 , thì điều này hoàn toàn sai lệch. Vì vậy, chỉ vì một cái gì đó là O (n ^ 2) không có nghĩa là bạn có thể tắt não và bỏ qua chức năng thực tế.cn2n2+1018

Mặt khác, nếu bạn chỉ gặp các giá trị n = 1, 2 và 3, thì trong thực tế, điều đó không tạo ra sự khác biệt mà f (n) làm cho n ≥ 4, vì vậy bạn cũng có thể xem xét rằng f ( n) = O (1), với c = max (f (1), f (2), f (3)). Và đó là những gì đủ nhỏ có nghĩa là: Nếu tuyên bố rằng f (n) = O (1) không đánh lừa bạn nếu các giá trị duy nhất của f (n) mà bạn gặp phải là "đủ nhỏ".


5

Nếu nó không phát triển, đó là O (1)

Tuyên bố của tác giả là một chút tiên đề.

Đơn đặt hàng tăng trưởng mô tả những gì xảy ra với số lượng công việc bạn phải làm khi Ntăng. Nếu bạn biết rằng Nkhông tăng, vấn đề của bạn là hiệu quả O(1).

Hãy nhớ rằng điều O(1)đó không có nghĩa là "nhanh". Một thuật toán luôn đòi hỏi 1 nghìn tỷ bước để hoàn thành O(1). Một thuật toán thực hiện bất cứ nơi nào từ 1-200 bước, nhưng không bao giờ nhiều hơn, là O(1). [1]

Nếu thuật toán của bạn thực hiện chính xác N ^ 3các bước và bạn biết rằng Nkhông thể nhiều hơn 5, thì nó không bao giờ có thể thực hiện nhiều hơn 125 bước, vì vậy nó rất hiệu quả O(1).

Nhưng một lần nữa, O(1)không nhất thiết có nghĩa là "đủ nhanh". Đó là một câu hỏi riêng biệt phụ thuộc vào bối cảnh của bạn. Nếu phải mất một tuần để hoàn thành một cái gì đó, có lẽ bạn không quan tâm nếu đó là về mặt kỹ thuật O(1).


[1] Ví dụ, tra cứu trong hàm băm là O(1), mặc dù các va chạm băm có nghĩa là bạn có thể phải xem qua một số mục trong một nhóm, miễn là có giới hạn cứng về số lượng mục có thể có trong nhóm đó.


1
Tất cả âm thanh đều hợp lệ, ngoại trừ điều này: "Nếu thuật toán của bạn thực hiện chính xác N ^ 3 bước và bạn biết rằng N không thể nhiều hơn 5, thì nó không bao giờ có thể mất hơn 125 bước, vì vậy đó là O (1)." . Một lần nữa, nếu một thuật toán lấy một số nguyên và hỗ trợ số nguyên tối đa của tôi là 32767, có phải là O (1) không? Rõ ràng là không. Big-O không thay đổi dựa trên giới hạn của các tham số. Đó là O (n) ngay cả khi bạn biết rằng 0 <n <3 vì n = 2 mất gấp đôi thời gian n = 1.
JSobell

3
@JSobell Nhưng đó là O (1). Nếu có một giới hạn giới hạn n của bạn đối với f (n), điều đó có nghĩa là nó không thể phát triển vô hạn. Nếu n của bạn bị giới hạn bởi 2 ^ 15 thì hàm n ^ 2 tuyệt vời của bạn thực sự g(n) = min(f(2^15), f(n))- nằm trong O (1). Điều đó nói rằng các hằng số thực tế rất quan trọng và rõ ràng n có thể trở nên đủ lớn để phân tích tiệm cận là hữu ích.
Voo

2
@JSobell Điều này tương tự như câu hỏi liệu máy tính có thực sự là "Turing Complete" hay không, vì về mặt kỹ thuật chúng không thể có không gian lưu trữ vô hạn. Về mặt kỹ thuật, về mặt toán học, máy tính không phải là một máy Turing "thật". Trong thực tế, không có thứ gọi là "băng vô hạn", nhưng ổ cứng đủ gần.
Kyle Strand

Tôi đã viết một hệ thống Rủi ro tài chính vài năm trước có liên quan đến n ^ 5 thao tác ma trận, do đó, có giới hạn thực tế là n = 20 trước khi tài nguyên trở thành một vấn đề.
JSobell

Xin lỗi, nhấn Enter quá sớm. Tôi đã viết một hệ thống Rủi ro tài chính vài năm trước có liên quan đến n ^ 5 thao tác ma trận, do đó, có giới hạn thực tế là n = 20 trước khi tài nguyên trở thành một vấn đề. Theo logic thiếu sót này, hàm được tạo là O (1) vì tôi có giới hạn là 20. Khi khách hàng nói "Hmm, có lẽ chúng ta nên di chuyển nó đến 40 như một giới hạn ... Yup, thuật toán là O (1 ) vì vậy không có vấn đề gì "... Đây là lý do tại sao giới hạn đầu vào là vô nghĩa. Hàm này là O (n ^ 5), không phải O (1) và đây là một ví dụ thực tế về lý do tại sao Big-O độc lập với giới hạn.
JSobell

2

Bây giờ, tôi có thể sử dụng hashtable và có O (1) tra cứu (bỏ qua việc triển khai cụ thể của hashtable), nhưng nếu tôi có ví dụ, một danh sách, tôi sẽ có tra cứu O (n). Với tiên đề này, hai cái này giống nhau nếu các bộ sưu tập đủ nhỏ. Nhưng đến một lúc nào đó chúng phân kỳ ... điểm đó là gì?

Thực tế, đó là điểm mà việc xây dựng bảng băm mất nhiều hơn lợi ích bạn có được từ việc tra cứu được cải thiện. Điều này sẽ thay đổi rất nhiều dựa trên tần suất bạn thực hiện tra cứu, so với tần suất bạn làm việc khác. O (1) so với O (10) không phải là vấn đề lớn nếu bạn làm điều đó một lần. Nếu bạn làm điều đó hàng ngàn lần một giây, thậm chí điều đó cũng quan trọng (mặc dù ít nhất nó cũng quan trọng với tốc độ tăng tuyến tính).


Nếu bạn muốn chắc chắn, hãy thực hiện một số thử nghiệm để xem cấu trúc dữ liệu nào tốt hơn cho các tham số của bạn .
Yuval Filmus

@Telastyn Yuval Filmus là đúng, nếu bạn thực sự muốn chắc chắn. Tôi biết một người tên Jim, thông số của anh ấy là ok. Nhưng anh không nghe lời khuyên như của Yuval. Bạn nên thực sự lắng nghe Yuval để chắc chắn và an toàn.
Thông báo

2

Trong khi trích dẫn là đúng (nhưng mơ hồ) cũng có những nguy hiểm đối với nó. Imo bạn nên nhìn vào sự phức tạp trong bất kỳ giai đoạn nào của ứng dụng của bạn.

Thật quá dễ để nói: hey tôi chỉ có một danh sách nhỏ, nếu tôi muốn kiểm tra xem mục A có trong danh sách không, tôi chỉ cần viết một vòng lặp dễ dàng để duyệt qua danh sách và so sánh các mục.

Sau đó, người bạn lập trình của bạn xuất hiện nhu cầu sử dụng danh sách, xem chức năng của bạn và giống như: hey tôi không muốn bất kỳ bản sao nào trong danh sách để anh ta sử dụng chức năng cho mọi mục được thêm vào danh sách.

(nhớ bạn, nó vẫn là một kịch bản danh sách nhỏ.)

3 năm sau tôi đi cùng và ông chủ của tôi vừa thực hiện một vụ mua bán lớn: phần mềm của chúng tôi sẽ được sử dụng bởi một nhà bán lẻ lớn của quốc gia. Trước đây chúng tôi chỉ phục vụ các cửa hàng nhỏ. Và bây giờ ông chủ của tôi đến chửi tôi và hét lên, tại sao phần mềm, thứ luôn "hoạt động tốt" bây giờ lại chậm đến mức khủng khiếp.

Hóa ra, danh sách đó là một danh sách khách hàng và khách hàng của chúng tôi chỉ có thể có 100 khách hàng, nên không ai để ý. Hoạt động điền vào danh sách về cơ bản là hoạt động O (1), vì mất ít hơn một phần nghìn giây. Chà, không quá nhiều khi có 10.000 khách hàng được thêm vào nó.

Và nhiều năm sau quyết định O (1) tồi tệ ban đầu, công ty gần như mất đi một khách hàng lớn. Tất cả chỉ vì một lỗi thiết kế / giả định ít năm trước.


Nhưng nó cũng minh họa một tính năng quan trọng của nhiều hệ thống trong thế giới thực: "thuật toán" mà bạn học khi còn là sinh viên thực sự là những mảnh ghép từ đó "thuật toán" thực sự được tạo ra. Điều này thường được gợi ý tại; ví dụ, hầu hết mọi người đều biết rằng quicksort thường được viết để quay trở lại sắp xếp chèn khi các phân vùng đủ nhỏ và tìm kiếm nhị phân thường được viết để quay lại tìm kiếm tuyến tính. Nhưng không nhiều người nhận ra rằng sắp xếp hợp nhất có thể được hưởng lợi từ một số tìm kiếm nhị phân.
Bút danh

1

Động lực để làm như vậy dựa trên ý tưởng không chính xác rằng O (1) luôn tốt hơn O (lg n), luôn tốt hơn O (n). Thứ tự tiệm cận của một hoạt động chỉ có liên quan nếu trong điều kiện thực tế, kích thước của vấn đề thực sự trở nên lớn.

Nếu tôi có hai thuật toán với những lần này:

  • log (n) +10000
  • n + 1

Sau đó, có một số điểm mà họ đi qua. Đối với nnhỏ hơn, thuật toán "tuyến tính" nhanh hơn và nlớn hơn, thuật toán "logarit" nhanh hơn. Nhiều người mắc sai lầm khi cho rằng thuật toán logarit nhanh hơn, nhưng với quy mô nhỏ nthì không.

Nếu n vẫn nhỏ thì mọi vấn đề là O (1)!

Tôi suy đoán điều có nghĩa ở đây là nếu nbị giới hạn, thì mọi vấn đề là O (1). Ví dụ: nếu chúng tôi sắp xếp các số nguyên, chúng tôi có thể chọn sử dụng quicksort. O(n*log(n))chắc chắn. Nhưng nếu chúng tôi quyết định rằng không bao giờ có nhiều hơn 2^64=1.8446744e+19số nguyên, thì chúng tôi biết rằng n*log(n)<= 1.8446744e+19*log(1.8446744e+19)<= 1.1805916e+21. Do đó, thuật toán sẽ luôn mất ít hơn 1.1805916e+21"đơn vị thời gian". Vì đó là thời gian không đổi, chúng ta có thể nói thuật toán luôn có thể được thực hiện trong thời gian không đổi đó -> O(1). (Lưu ý rằng ngay cả khi các đơn vị thời gian đó là nano giây, đó là tổng cộng hơn 37411 năm). Nhưng vẫn vậy O(1).


0

Tôi nghi ngờ nhiều câu trả lời trong số này đang thiếu một khái niệm cơ bản. O (1): O (n) không giống với f (1): f (n) trong đó f là cùng một hàm, vì O không đại diện cho một hàm duy nhất. Ngay cả biểu đồ đẹp của Schwern cũng không hợp lệ vì nó có cùng trục Y cho tất cả các dòng. Để sử dụng cùng một trục, các dòng sẽ phải là fn1, fn2 và fn3, trong đó mỗi dòng là một hàm có hiệu năng có thể được so sánh trực tiếp với các dòng khác.

Tôi đã nghe nhiều lần rằng với các giá trị đủ nhỏ của n, O (n) có thể được nghĩ về / đối xử như thể đó là O (1)

Chà, nếu n = 1 chúng có giống hệt nhau không? Không. Một hàm cho phép số lần lặp khác nhau không có gì giống với hàm không, ký hiệu big-O không quan tâm, và chúng ta cũng không nên.

Ký hiệu Big-O chỉ đơn giản là ở đó để diễn tả những gì xảy ra khi chúng ta có một quy trình lặp và hiệu suất (thời gian hoặc tài nguyên) sẽ giảm xuống như thế nào khi tăng 'n'.

Vì vậy, để trả lời câu hỏi thực tế ... Tôi sẽ nói rằng những người đưa ra yêu cầu đó không hiểu đúng về ký hiệu Big-O, bởi vì đó là một so sánh phi logic.

Đây là một câu hỏi tương tự: Nếu tôi lặp qua một chuỗi ký tự và tôi biết rằng nói chung các chuỗi của tôi sẽ có ít hơn 10 ký tự, tôi có thể nói rằng nó tương đương với O (1) không, nhưng nếu chuỗi của tôi dài hơn thì tôi 'muốn nói đó là O (n)?

Không, bởi vì một chuỗi gồm 10 ký tự mất 10 lần chuỗi dài 1 ký tự, nhưng ít hơn 100 lần so với chuỗi 1000 ký tự! Đó là O (n).


Trên thực tế, nếu bạn biết rằng đầu vào của bạn sẽ có tối đa 10 ký tự, bạn có thể viết mộtÔi(1)thuật toán. Đầu tiên, hãy kiểm tra xem có nhiều nhất 10 ký tự không; nếu không, bạn có thể từ chối mà không cần nhìn vào phần còn lại. Bây giờ, nếu nó cầnf(tôi) các bước để xử lý đầu vào của tôi ký tự, thời gian chạy còn lại của bạn được đưa ra bởi tối đa{f(0),Giáo dục,f(10)}. Đó là một hằng số, đó làÔi(1).
David Richerby 17/12/14

Vâng, và đây là một ví dụ về nơi ký hiệu Big-O thường bị hiểu lầm. Theo lập luận của bạn, nếu tôi biết rằng giá trị tối đa của n là 1.000.000, thì hàm của tôi là O (1). Trên thực tế, chức năng của tôi có thể ở mức tốt nhất O (1) và tồi tệ nhất là O (n). Ký hiệu này được sử dụng để mô tả độ phức tạp thuật toán, không phải là một triển khai cụ thể và chúng tôi luôn sử dụng cái đắt nhất để mô tả một kịch bản, không phải là tốt nhất. Trong thực tế, theo đối số của bạn, mọi hàm duy nhất cho phép n <2 là O (1)! :)
JSobell

Không. Ký hiệu Big-O được sử dụng để mô tả tốc độ tăng trưởng của các chức năng. Những chức năng này có thể được sử dụng để đo lường mọi thứ. Và tôi chắc chắn đã không tranh luận rằng "mọi chức năng cho phépn<2 [bất cứ điều gì có nghĩa] là Ôi(1). "Thực tế tôi lập luận rằng bất kỳ chức năng nào có thuộc tính f(n)f(10) cho tất cả nÔi(1), cái nào đúng.
David Richerby 17/12/14

Sorry, but if you say that knowing the upper bounds of n makes a function O(1), then you are saying that the notational representation is directly related to the value of n, and it's not. Everything else you mention is correct, but suggesting that because n has bounds it's O(1) is not correct. In practice there are places where what you describe may be observable, but we are looking at Big-O notation here, not functional coding. So again, why would you suggest that n having a max of 10 would make it O(1)? Why 10? Why not 65535, or 2^64?
JSobell

Phải nói rằng, nếu bạn viết một hàm đệm một chuỗi thành 10 ký tự, thì luôn luôn lặp trên chuỗi, thì đó là O (1) vì n luôn là 10 :)
JSobell 17/12/14

0

I believe the text you quoted is quite inacurrate (using the word "better" is usually meaningless unless you provide the context: in terms of time, space etc.) Anyway, I believe the simplest explanation would be:

If time of execution grows with the size of an input then it is definitely not O(1) and that should be clear. O(1) does not mean fast. It just means (in terms of time complexity) that time of execution has a constant upper bound.

Now, let's take a relatively small set of 10 elements and have a few algorithms to sort it (just an example). Let's assume that we keep the elements in a structure that also provides us with an algorithm capable of sorting the elements in constant time. Let's say our sorting-algorithms can have following complexities (with big-O notation):

  1. O(1)
  2. O(n)
  3. O(nlog(n))
  4. O(n2)

Which algoritm would you choose? The first answer that comes to mind may be "of course I'll use the O(1) one!", but this is not necessarily correct. What you forget when thinking like that is that the big-O notation hides the constant factor. And if you know your set is pretty small, then this constant factor may be much more important than the asympthotic complexity.

Now let's "reveal" the true complexities of that sorting algorithms mentioned above (where "true" means not hiding the constant), represented by numbers of steps required to finish (and assume all steps take the same amount of time):

  1. 200 steps
  2. 11n steps
  3. 4nlog(n) steps (log with base 2)
  4. 1n2 steps

If our input is of size 10, then these are exact amounts of steps for every algorithm mentioned above:

  1. 200 steps
  2. 11×10=110 steps
  3. 4×10×3.32134 steps
  4. 1×100=100 steps

As you see, in this case the apparently worst algorithm with asympthotic complexity O(n2) is the fastest one, beating algorithms with O(1),O(n) and O(nlog(n)) asympthotic complexities. The constant factor hidden by the big-O notation matters here. In my opinion it does not mean that we can treat O(n2) as better than O(1) (what would it mean anyway?) It means that for sufficiently small input (like you've seen in the example) the O(n2) may still be faster than O(1) because of the hidden constant. And if the constant is relatively large compared to the size of the input, it may matter more than the asympthotic complexity.

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.