Có bất kỳ thuật toán O (1 / n) nào không?


335

Có bất kỳ thuật toán O (1 / n) nào không?

Hoặc bất cứ điều gì khác ít hơn O (1)?


Hầu hết các câu hỏi cho rằng bạn có nghĩa là "Có thuật toán nào có độ phức tạp thời gian là O (1 / n) không?" Chúng ta sẽ cho rằng đây là trường hợp? Big-O (và Big-Theta, v.v.) mô tả các hàm, không phải thuật toán. (Tôi biết không có sự tương đương giữa các hàm và thuật toán.)
jyoungdev

4
Đó là định nghĩa thường được hiểu về "thuật toán O (X)" trong khoa học máy tính: một thuật toán có độ phức tạp thời gian là O (X) (đối với một số biểu thức X).
David Z

2
Tôi đã nghe thấy ràng buộc như vậy trong trường hợp thuật toán hàng đợi ưu tiên hiệu quả I / O sử dụng Buffer Tree. Trong Cây đệm, mỗi thao tác lấy O (1 / B) I / O; Trong đó B là kích thước khối. Và tổng I / O cho n thao tác là O (n / B.log (cơ sở M / B) (n / B)), trong đó phần log là chiều cao của cây đệm.
CODError

Có rất nhiều thuật toán với xác suất lỗi O (1 / n). Ví dụ: bộ lọc nở với các thùng O (n log n).
Thomas Ahle

Bạn không thể đẻ trứng nhanh hơn bằng cách thêm gà.
Wyck

Câu trả lời:


310

Câu hỏi này không ngu ngốc như nó có vẻ. Ít nhất về mặt lý thuyết, một cái gì đó như O (1 / n ) là hoàn toàn hợp lý khi chúng ta lấy định nghĩa toán học của ký hiệu Big O :

Bây giờ bạn có thể dễ dàng thay thế g ( x ) cho 1 / x Rõ ràng là định nghĩa trên vẫn đúng với một số f .

Với mục đích ước tính tăng trưởng thời gian chạy không có triệu chứng, điều này ít khả thi hơn, một thuật toán có ý nghĩa không thể nhanh hơn khi đầu vào phát triển. Chắc chắn, bạn có thể xây dựng một thuật toán tùy ý để thực hiện điều này, ví dụ: thuật toán sau:

def get_faster(list):
    how_long = (1 / len(list)) * 100000
    sleep(how_long)

Rõ ràng, chức năng này dành ít thời gian hơn khi kích thước đầu vào tăng ít nhất cho đến khi giới hạn nào đó, được thực thi bởi phần cứng (độ chính xác của các số, thời gian tối thiểu sleepcó thể chờ, thời gian để xử lý đối số, v.v.): giới hạn này sẽ là một hằng số giới hạn dưới nên trong thực tế hàm trên vẫn có thời gian chạy O (1).

Nhưng có trên thực tế thuật toán thực thế giới mà thời gian chạy có thể làm giảm (ít nhất là một phần) khi kích thước đầu vào tăng. Lưu ý rằng các thuật toán này sẽ không thể hiện hành vi thời gian chạy bên dưới O (1). Tuy nhiên, chúng là thú vị. Ví dụ: lấy thuật toán tìm kiếm văn bản rất đơn giản của Horspool . Ở đây, thời gian chạy dự kiến ​​sẽ giảm khi chiều dài của mẫu tìm kiếm tăng (nhưng tăng độ dài của haystack sẽ một lần nữa tăng thời gian chạy).


22
'Được thực thi bởi phần cứng' cũng áp dụng cho Máy Turing. Trong trường hợp O (1 / n) sẽ luôn có một kích thước đầu vào mà thuật toán không được phép thực hiện bất kỳ thao tác nào. Và do đó tôi sẽ nghĩ rằng độ phức tạp thời gian O (1 / n) thực sự là không thể đạt được.
Roland Ewald

28
Mehrdad, bạn không hiểu. Ký hiệu O là một cái gì đó về giới hạn (về mặt kỹ thuật lim sup) là n ->. Thời gian chạy của thuật toán / chương trình là số bước trên một số máy và do đó rời rạc - có giới hạn thấp hơn không về thời gian mà thuật toán có thể thực hiện ("một bước"). Đó có thể là tối đa một số hữu hạn N một chương trình có một số bước giảm với n, nhưng chỉ cách một thuật toán có thể được O (1 / n), hoặc thực sự o (1), là nếu nó đòi hỏi thời gian 0 cho tất cả đầy đủ n lớn - điều không thể.
ShreevatsaR

28
Chúng tôi không đồng ý rằng O (1 / n) chức năng (theo nghĩa toán học) tồn tại. Rõ ràng là họ làm. Nhưng tính toán vốn đã rời rạc. Một cái gì đó có giới hạn thấp hơn, chẳng hạn như thời gian chạy chương trình - trên kiến ​​trúc von Neumann hoặc máy Turing hoàn toàn trừu tượng - không thể là O (1 / n). Tương tự, một cái gì đó là O (1 / n) không thể có giới hạn thấp hơn. (Chức năng "ngủ" của bạn phải được gọi hoặc "danh sách" biến phải được kiểm tra - hoặc băng đầu vào phải được kiểm tra trên máy Turing. Vì vậy, thời gian thực hiện sẽ thay đổi với n là + 1 / n, không phải là O (1 / n))
ShreevatsaR

16
Nếu T (0) =, nó không dừng lại. Không có thứ gọi là "T (0) =, nhưng nó vẫn dừng lại". Hơn nữa, ngay cả khi bạn làm việc trong R∪ {} và xác định T (0) = và T (n + 1) = T (n) / 2, thì T (n) = với mọi n. Tôi xin nhắc lại: nếu một hàm có giá trị rời rạc là O (1 / n), thì với tất cả n đủ lớn thì nó là 0. [Chứng minh: T (n) = O (1 / n) có nghĩa là tồn tại hằng số c sao cho với n> N0, T (n) <c (1 / n), có nghĩa là với mọi n> max (N0,1 / c), T (n) <1, có nghĩa là T (n) = 0.] không có máy, thực hay trừu tượng, có thể mất thời gian 0: nó nhìn vào các đầu vào. Chà, ngoài cái máy không bao giờ làm gì cả, và T (n) = 0 cho tất cả n.
ShreevatsaR

43
Bạn phải thích bất kỳ câu trả lời nào bắt đầu "Câu hỏi này không ngu ngốc như vẻ ngoài của nó."
Telemachus

138

Đúng.

Có chính xác một thuật toán với thời gian chạy O (1 / n), thuật toán "trống".

Đối với một thuật toán là O (1 / n) có nghĩa là nó thực thi bất đối xứng trong các bước ít hơn so với thuật toán bao gồm một lệnh đơn. Nếu nó thực hiện trong ít bước hơn một bước cho tất cả n> n0, thì nó phải bao gồm chính xác không có hướng dẫn nào cho n. Vì việc kiểm tra 'if n> n0' tốn ít nhất 1 lệnh, nên nó không bao gồm lệnh nào cho tất cả n.

Tổng hợp: Các thuật toán duy nhất là O (1 / n) là thuật toán có sản phẩm nào, bao gồm không có hướng dẫn.


2
Vì vậy, nếu ai đó hỏi độ phức tạp thời gian của thuật toán trống là gì, bạn sẽ trả lời bằng O (1 / n) ??? Bằng cách nào đó tôi nghi ngờ điều đó.
phkahler

24
Đây là câu trả lời đúng duy nhất trong chủ đề này, và (mặc dù upvote của tôi) nó không có phiếu bầu. Chẳng hạn như StackOverflow, trong đó các câu trả lời "nhìn đúng" được bình chọn cao hơn so với câu trả lời đúng.
ShreevatsaR

5
Không, nó được đánh giá 0 vì nó không chính xác. Biểu thị giá trị Oh lớn liên quan đến N khi nó độc lập với N là không chính xác. Thứ hai, chạy bất kỳ chương trình nào, thậm chí một chương trình chỉ tồn tại, mất ít nhất một lượng thời gian không đổi, O (1). Ngay cả khi đó không phải là trường hợp, nó sẽ là O (0), không phải O (1 / n).
kenj0418

32
Bất kỳ hàm nào là O (0) cũng là O (1 / n), và cả O (n), cũng là O (n ^ 2), cũng là O (2 ^ n). Thở dài, không ai hiểu định nghĩa đơn giản? O () là một giới hạn trên.
ShreevatsaR

16
@ kenj0418 Bạn đã quản lý sai trong mỗi câu. "Biểu thị giá trị Oh lớn liên quan đến N khi nó độc lập với N là không chính xác." Một hàm hằng là một hàm hoàn hảo. "Thứ hai, chạy bất kỳ chương trình nào, thậm chí một chương trình chỉ tồn tại, mất ít nhất một lượng thời gian không đổi, O (1)." Định nghĩa về độ phức tạp không nói lên điều gì về việc thực sự chạy bất kỳ chương trình nào. "Nó sẽ là O (0), không phải O (1 / n)". Xem bình luận của @ ShreevatsaR.
Alexey Romanov

25

sharptooth là chính xác, O (1) là hiệu suất tốt nhất có thể. Tuy nhiên, nó không ngụ ý một giải pháp nhanh, chỉ là một giải pháp thời gian cố định.

Một biến thể thú vị, và có lẽ những gì thực sự được đề xuất, là vấn đề trở nên dễ dàng hơn khi dân số tăng lên. Tôi có thể nghĩ về 1, mặc dù câu trả lời và câu trả lời:

Có ai trong một bộ có cùng ngày sinh không? Khi n vượt quá 365, trả về true. Mặc dù với ít hơn 365, đây là O (n ln n). Có lẽ không phải là một câu trả lời hay vì vấn đề không dần trở nên dễ dàng hơn mà chỉ trở thành O (1) cho n> 365.


7
365. Đừng quên những năm nhuận!
Nick Johnson

1
Bạn nói đúng. Giống như máy tính, đôi khi tôi cũng gặp phải lỗi làm tròn :-)
Adrian

10
+1. Có một số vấn đề hoàn thành NP trải qua "quá trình chuyển pha" khi n tăng, tức là chúng nhanh chóng trở nên dễ dàng hơn hoặc khó hơn nhiều khi bạn vượt quá một giá trị ngưỡng nhất định là n. Một ví dụ là Bài toán phân vùng số: đưa ra một tập hợp n số nguyên không âm, phân vùng chúng thành hai phần sao cho tổng của mỗi phần bằng nhau. Điều này trở nên dễ dàng hơn đáng kể ở một giá trị ngưỡng nhất định của n.
j_random_hacker

23

Đó là không thể. Định nghĩa của Big-O không lớn hơn bất bình đẳng:

A(n) = O(B(n))
<=>
exists constants C and n0, C > 0, n0 > 0 such that
for all n > n0, A(n) <= C * B(n)

Vì vậy, B (n) trên thực tế là giá trị tối đa, do đó nếu nó giảm khi n tăng thì ước lượng sẽ không thay đổi.


42
Tôi nghi ngờ câu trả lời này là "đúng", nhưng tiếc là tôi thiếu trí tuệ để hiểu nó.
năm09

12
AFAIK điều kiện này không phải đúng với tất cả n, nhưng với tất cả n> n_0 (nghĩa là chỉ khi kích thước của đầu vào đạt đến một ngưỡng cụ thể).
Roland Ewald

30
Tôi không thấy định nghĩa (thậm chí đã sửa) mâu thuẫn với câu hỏi của OP. Định nghĩa giữ cho các chức năng hoàn toàn tùy ý! 1 / n là một hàm hoàn toàn hợp lý cho B, và trên thực tế phương trình của bạn không mâu thuẫn với điều đó (chỉ làm toán). Vì vậy, không, mặc dù có nhiều sự đồng thuận, nhưng câu trả lời này thực tế là sai . Lấy làm tiếc.
Konrad Rudolph

10
Sai lầm! Tôi không thích hạ thấp nhưng bạn nói rằng điều này là không thể khi không có sự đồng thuận rõ ràng. Trong thực tế, bạn đã đúng, nếu bạn xây dựng một hàm với thời gian chạy 1 / n (dễ dàng) thì cuối cùng nó sẽ đạt được một số thời gian tối thiểu, thực sự biến nó thành thuật toán O (1) khi được thực hiện. Không có gì để ngăn thuật toán trở thành O (1 / n) trên giấy.
jheriko

3
@Jason: Đúng, bây giờ bạn nói điều đó ... :) @jheriko: Độ phức tạp thời gian của O (1 / n) không hoạt động trên giấy IMHO. Chúng tôi đang mô tả chức năng tăng trưởng f (kích thước đầu vào) = #ops cho máy Turing. Nếu nó dừng lại với đầu vào có độ dài n = 1 sau x bước, thì tôi sẽ chọn kích thước đầu vào n >> x, tức là đủ lớn, nếu thuật toán thực sự ở O (1 / n), thì không nên thực hiện thao tác nào làm xong. Làm thế nào một máy Turing thậm chí nhận thấy điều này (nó không được phép đọc một lần từ băng)?
Roland Ewald

16

Từ việc học trước đây của tôi về ký hiệu O lớn, ngay cả khi bạn cần 1 bước (chẳng hạn như kiểm tra một biến, thực hiện một bài tập), đó là O (1).

Lưu ý rằng O (1) giống với O (6), vì "hằng số" không thành vấn đề. Đó là lý do tại sao chúng ta nói O (n) giống với O (3n).

Vì vậy, nếu bạn cần 1 bước, đó là O (1) ... và vì chương trình của bạn ít nhất cần 1 bước, thuật toán tối thiểu có thể đi là O (1). Trừ khi chúng ta không làm điều đó, thì đó là O (0), tôi nghĩ sao? Nếu chúng ta làm bất cứ điều gì, thì đó là O (1), và đó là mức tối thiểu có thể đi.

(Nếu chúng ta chọn không làm điều đó, thì nó có thể trở thành một câu hỏi Zen hoặc Tao ... trong lĩnh vực lập trình, O (1) vẫn là mức tối thiểu).

Hoặc làm thế nào về điều này:

lập trình viên : ông chủ, tôi đã tìm ra cách để làm điều đó trong thời gian O (1)!
ông chủ : không cần làm điều đó, chúng tôi phá sản sáng nay.
lập trình viên : oh sau đó, nó trở thành O (0).


Trò đùa của bạn làm tôi nhớ đến một cái gì đó từ Đạo lập trình: canonical.org/~kragen/tao-of-programming.html#book8 (8.3)
kenj0418

Một thuật toán bao gồm các bước không là O (0). Đó là một thuật toán rất lười biếng.
nalply

8

Không, điều này là không thể:

Khi n có xu hướng vô cùng trong 1 / n, cuối cùng chúng ta đạt được 1 / (inf), có hiệu quả là 0.

Do đó, lớp lớn của vấn đề sẽ là O (0) với n lớn, nhưng gần với thời gian không đổi với n thấp. Điều này là không hợp lý, vì điều duy nhất có thể được thực hiện trong thời gian nhanh hơn thời gian không đổi là:

void nothing() {};

Và thậm chí điều này là tranh cãi!

Ngay khi bạn thực thi một lệnh, bạn sẽ có ít nhất O (1), vì vậy không, chúng ta không thể có một lớp O (1 / n) lớn!


7

Điều gì về việc không chạy chức năng nào cả (NOOP)? hoặc sử dụng một giá trị cố định. Có tính không?


16
Đó vẫn là O (1) thời gian chạy.
Konrad Rudolph

2
Phải, đó vẫn là O (1). Tôi không thấy làm thế nào một người nào đó có thể hiểu điều này, và tuyên bố trong một câu trả lời khác rằng một cái gì đó ít hơn NO-OP là có thể.
ShreevatsaR

4
ShreevatsaR: hoàn toàn không có mâu thuẫn. Bạn dường như không nắm bắt được rằng ký hiệu O lớn không liên quan gì đến thời gian dành cho hàm - thay vào đó, nó mô tả cách thời gian đó thay đổi khi thay đổi đầu vào (trên một giá trị nhất định). Xem chủ đề bình luận khác để biết thêm.
Konrad Rudolph

Tôi nắm bắt nó hoàn toàn tốt, cảm ơn bạn. Điểm - như tôi đã thực hiện nhiều lần trong luồng khác - là nếu thời gian giảm với đầu vào, ở tốc độ O (1 / n), thì cuối cùng nó phải giảm xuống dưới thời gian của NOOP. Điều này cho thấy rằng không có thuật toán nào có thể là O (1 / n) không có triệu chứng, mặc dù chắc chắn thời gian chạy của nó có thể giảm đến giới hạn.
ShreevatsaR

1
Có ... như tôi đã nói ở nơi khác, bất kỳ thuật toán nào là O (1 / n) cũng sẽ không mất thời gian cho tất cả các đầu vào, do đó tùy thuộc vào việc bạn có xem xét thuật toán null mất 0 thời gian hay không, có O (1 / n) thuật toán. Vì vậy, nếu bạn coi NOOP là O (1), thì không có thuật toán O (1 / n).
ShreevatsaR

7

Tôi thường sử dụng O (1 / n) để mô tả các xác suất trở nên nhỏ hơn khi các đầu vào trở nên lớn hơn - ví dụ: xác suất mà một đồng xu công bằng xuất hiện trên các lần lật log2 (n) là O (1 / n).


6
Đó không phải là những gì O lớn. Bạn không thể xác định lại nó để trả lời câu hỏi.
Zifre

11
Đây không phải là định nghĩa lại, đó chính xác là định nghĩa của O.
ShreevatsaR

10
Tôi là một nhà khoa học máy tính lý thuyết bằng thương mại. Đó là về thứ tự tiệm cận của một chức năng.
Dave

4
Big O là một tài sản của một hàm thực tùy ý. Độ phức tạp thời gian chỉ là một trong những ứng dụng khả thi của nó. Độ phức tạp không gian (số lượng bộ nhớ làm việc mà thuật toán sử dụng) là khác. Câu hỏi đặt ra là về thuật toán O (1 / n) ngụ ý rằng đó là một trong những thuật toán này (trừ khi có một thuật toán khác áp dụng cho các thuật toán mà tôi không biết). Các ứng dụng khác bao gồm các đơn đặt hàng tăng dân số, ví dụ như trong Cuộc sống của Conway. Xem thêm en.wikipedia.org/wiki/Big_O_notation
Stewart

5
@Dave: Câu hỏi không phải là có tồn tại các hàm O (1 / n) hay không, mà rõ ràng là có tồn tại. Thay vào đó, đó là liệu có tồn tại thuật toán O (1 / n) hay không, mà (với ngoại lệ có thể có của hàm null) không thể tồn tại
Casebash

6

O (1) đơn giản có nghĩa là "thời gian không đổi".

Khi bạn thêm một lối thoát sớm vào một vòng lặp [1], bạn (theo ký hiệu big-O) biến thuật toán O (1) thành O (n), nhưng làm cho nó nhanh hơn.

Thủ thuật nói chung là thuật toán thời gian không đổi là tốt nhất và tuyến tính tốt hơn theo cấp số nhân, nhưng với số lượng nhỏ n, thuật toán hàm mũ thực sự có thể nhanh hơn.

1: Giả sử độ dài danh sách tĩnh cho ví dụ này


6

Đối với bất kỳ ai đọc câu hỏi này và muốn hiểu cuộc trò chuyện nói về điều gì, điều này có thể giúp:

|    |constant |logarithmic |linear|  N-log-N |quadratic|  cubic  |  exponential  |
|  n |  O(1)   | O(log n)   | O(n) |O(n log n)|  O(n^2) |  O(n^3) |     O(2^n)    |
|  1 |       1 |          1 |     1|         1|        1|       1 |             2 |
|  2 |       1 |          1 |     2|         2|        4|       8 |             4 |
|  4 |       1 |          2 |     4|         8|       16|      64 |            16 |
|  8 |       1 |          3 |     8|        24|       64|     512 |           256 |
| 16 |       1 |          4 |    16|        64|      256|   4,096 |         65536 |
| 32 |       1 |          5 |    32|       160|    1,024|  32,768 | 4,294,967,296 |
| 64 |       1 |          6 |    64|       384|    4,069| 262,144 |   1.8 x 10^19 |

5

Tôi tin rằng các thuật toán lượng tử có thể thực hiện nhiều phép tính "cùng một lúc" thông qua sự chồng chất ...

Tôi nghi ngờ đây là một câu trả lời hữu ích.


Đó vẫn sẽ là thời gian không đổi, tức là O (1), nghĩa là phải mất cùng thời gian để chạy dữ liệu có kích thước n giống như đối với dữ liệu có kích thước 1.
freespace

2
Nhưng nếu vấn đề là ale nhạt thì sao? (ah. hah. ha.)
Jeff Meatball Yang

7
Đó sẽ là một vị trí siêu hạng.
Daniel Earwicker

1
Các thuật toán lượng tử có thể thực hiện nhiều phép tính, nhưng bạn chỉ có thể truy xuất kết quả của một phép tính và bạn không thể chọn kết quả nào sẽ nhận được. Rất may, bạn cũng có thể thực hiện các thao tác trên toàn bộ đăng ký lượng tử (ví dụ: QFT) để bạn dễ dàng tìm thấy thứ gì đó hơn :)
Gracenotes

2
nó có thể không hữu ích, nhưng nó có lợi thế là đúng, nó đặt nó trên một số câu trả lời được đánh giá cao hơn B-)
Brian Postow

4

Nhiều người đã có câu trả lời đúng (Không) Đây là một cách khác để chứng minh điều đó: Để có chức năng, bạn phải gọi chức năng đó và bạn phải trả lời câu trả lời. Điều này cần một lượng thời gian nhất định. NGAY CẢ NẾU phần còn lại của quá trình xử lý mất ít thời gian hơn cho các đầu vào lớn hơn, việc in ra câu trả lời (mà chúng ta có thể giả sử là một bit) mất ít nhất thời gian không đổi.


2

Nếu giải pháp tồn tại, nó có thể được chuẩn bị và truy cập trong thời gian không đổi = ngay lập tức. Chẳng hạn, sử dụng cấu trúc dữ liệu LIFO nếu bạn biết truy vấn sắp xếp là theo thứ tự ngược lại. Sau đó, dữ liệu đã được sắp xếp, với điều kiện là mô hình thích hợp (LIFO) đã được chọn.


2

Những vấn đề nào trở nên dễ dàng hơn khi dân số tăng lên? Một câu trả lời là một thứ giống như bittorrent trong đó tốc độ tải xuống là một hàm nghịch đảo của số lượng nút. Trái ngược với một chiếc xe hơi, nó làm chậm bạn tải nó nhiều hơn, một mạng chia sẻ tệp như bittorrent tăng tốc độ các nút được kết nối nhiều hơn.


Có, nhưng số lượng nút bittorrent giống như số lượng bộ xử lý trong một máy tính song song. "N" trong trường hợp này sẽ là kích thước của tệp đang cố tải xuống. Giống như bạn có thể tìm thấy một phần tử trong một mảng có độ dài N chưa được sắp xếp trong thời gian không đổi nếu bạn có N máy tính, bạn có thể tải xuống tệp Size N trong thời gian không đổi nếu bạn có N máy tính cố gửi dữ liệu cho bạn.
Kibbee

2

Bạn không thể xuống dưới O (1), tuy nhiên O (k) trong đó k nhỏ hơn N là có thể. Chúng tôi gọi chúng là thuật toán thời gian tuyến tính . Trong một số vấn đề, thuật toán thời gian tuyến tính chỉ có thể đưa ra các giải pháp gần đúng cho một vấn đề cụ thể. Tuy nhiên, đôi khi, một giải pháp gần đúng là tốt, có thể là do tập dữ liệu quá lớn hoặc quá tốn kém để tính toán tất cả.


1
Không chắc là tôi hiểu. Log (N) nhỏ hơn N. Điều đó có nghĩa là Log (N) là thuật toán tuyến tính? Và nhiều thuật toán Log (N) tồn tại. Một ví dụ như vậy là tìm giá trị trong cây nhị phân. Tuy nhiên, những điều này vẫn khác với 1 / N, vì Log (N) luôn tăng, trong khi 1 / n là hàm giảm.
Kibbee

Nhìn vào định nghĩa, thuật toán thời gian tuyến tính là bất kỳ thuật toán nào có thời gian tăng chậm hơn kích thước N. Vì vậy, bao gồm thuật toán thời gian logarit, đó là Log (N).
Hao Wooi Lim

2
Uh, thuật toán thời gian tuyến tính có thể đưa ra câu trả lời chính xác, ví dụ tìm kiếm nhị phân trong một mảng có thứ tự trên máy RAM.
A. Rex

@A. Rex: Hao Wooi Lim nói "Trong một số vấn đề".
LarsH

1

Cái này thì sao:

void FindRandomInList(list l)
{
    while(1)
    {
        int rand = Random.next();
        if (l.contains(rand))
            return;
    }
}

khi kích thước của danh sách tăng lên, thời gian chạy dự kiến ​​của chương trình sẽ giảm.


tôi nghĩ bạn không hiểu ý nghĩa của O (n)
Markus Lausberg

Mặc dù không phải với danh sách, với mảng hoặc hàm băm constainslà O (1)
vava

ok, hàm ngẫu nhiên có thể được coi là một mảng lười biếng, vì vậy về cơ bản bạn đang tìm kiếm từng phần tử trong "danh sách ngẫu nhiên lười biếng" và kiểm tra xem nó có trong danh sách đầu vào không. Tôi nghĩ rằng điều này là tồi tệ hơn tuyến tính, không tốt hơn.
hasen

Anh ta sẽ nhận được một số điểm nếu bạn nhận thấy int có bộ giá trị giới hạn. Vì vậy, khi tôi sẽ chứa 2 giá trị <sup> 64 </ sup>, nó sẽ ngay lập tức hoàn toàn. Điều này làm cho nó tệ hơn O (1) dù sao đi nữa :)
vava

1

O (1 / n) không nhỏ hơn O (1), về cơ bản có nghĩa là bạn càng có nhiều dữ liệu, thuật toán càng nhanh. Giả sử bạn nhận được một mảng và luôn điền vào tối đa 10 100 phần tử nếu nó có ít hơn và không làm gì nếu có nhiều hơn. Tất nhiên, đây không phải là O (1 / n) mà là một cái gì đó như O (-n) :) Ký hiệu O-big quá tệ không cho phép các giá trị âm.


1
"O (1 / n) không nhỏ hơn O (1)" - nếu hàm f là O (1 / n), thì đó cũng là O (1). Và big-oh cảm thấy rất giống một mối quan hệ "nhỏ hơn": đó là phản xạ, nó mang tính bắc cầu và nếu chúng ta có sự đối xứng giữa f và g thì hai tương đương nhau, trong đó big-theta là mối quan hệ tương đương của chúng ta. Quan hệ đặt hàng "thực" của ISTR yêu cầu a <= b và b <= a để ngụ ý a = b, và netcraft ^ W wikipedia xác nhận điều đó. Vì vậy, theo một nghĩa nào đó, thật công bằng khi nói rằng thực sự O (1 / n) là "ít hơn" O (1).
Jonas Kölker

1

Như đã chỉ ra, ngoài ngoại lệ có thể có của hàm null, không thể có O(1/n)chức năng nào , vì thời gian thực hiện sẽ phải tiếp cận 0.

Tất nhiên, có một số thuật toán, giống như được xác định bởi Konrad, có vẻ như chúng nên ít hơn O(1)trong một số ý nghĩa.

def get_faster(list):
    how_long = 1/len(list)
    sleep(how_long)

Nếu bạn muốn điều tra các thuật toán này, bạn nên xác định phép đo tiệm cận của riêng bạn hoặc khái niệm thời gian của riêng bạn. Ví dụ, trong thuật toán trên, tôi có thể cho phép sử dụng một số thao tác "miễn phí" trong một khoảng thời gian đã đặt. Trong thuật toán trên, nếu tôi xác định t 'bằng cách loại trừ thời gian cho mọi thứ trừ giấc ngủ, thì t' = 1 / n, đó là O (1 / n). Có lẽ có những ví dụ tốt hơn, vì hành vi tiệm cận là tầm thường. Trên thực tế, tôi chắc chắn rằng ai đó ngoài kia có thể đưa ra các giác quan mang lại kết quả không hề nhỏ.


1

Hầu hết các câu trả lời còn lại diễn giải big-O chỉ dành riêng cho thời gian chạy của thuật toán. Nhưng vì câu hỏi không đề cập đến nó, tôi nghĩ rằng đáng để đề cập đến ứng dụng khác của big-O trong phân tích số, đó là về lỗi.

Nhiều thuật toán có thể là O (h ^ p) hoặc O (n ^ {- p}) tùy thuộc vào việc bạn đang nói về kích thước bước (h) hay số lần phân chia (n). Ví dụ: trong phương pháp Euler , bạn tìm ước tính y (h) cho rằng bạn biết y (0) và dy / dx (đạo hàm của y). Ước tính của bạn về y (h) chính xác hơn, h gần hơn đến 0. Vì vậy, để tìm y (x) cho một số x tùy ý, người ta lấy khoảng 0 đến x, tách nó ra cho đến khi n mảnh và chạy phương thức Euler tại mỗi điểm, để chuyển từ y (0) đến y (x / n) đến y (2x / n), v.v.

Vì vậy, phương pháp của Euler là thuật toán O (h) hoặc O (1 / n), trong đó h thường được hiểu là kích thước bước và n được hiểu là số lần bạn chia một khoảng.

Bạn cũng có thể có O (1 / h) trong các ứng dụng phân tích số thực, do các lỗi làm tròn dấu phẩy động . Bạn thực hiện khoảng thời gian của mình càng nhỏ, việc hủy bỏ xảy ra càng nhiều đối với việc thực hiện một số thuật toán nhất định, mất nhiều chữ số có nghĩa hơn và do đó càng có nhiều lỗi được truyền qua thuật toán.

Đối với phương pháp của Euler, nếu bạn đang sử dụng các dấu phẩy động, hãy sử dụng một bước đủ nhỏ và hủy bỏ và bạn đang thêm một số nhỏ vào một số lớn, giữ nguyên số lớn. Đối với các thuật toán tính đạo hàm thông qua phép trừ hai số khác từ một hàm được đánh giá ở hai vị trí rất gần nhau, xấp xỉ y '(x) với (y (x + h) - y (x) / h), trong các hàm trơn y (x + h) gần với y (x) dẫn đến hủy lớn và ước tính cho đạo hàm có số liệu ít quan trọng hơn. Điều này sẽ lần lượt lan truyền đến bất kỳ thuật toán nào bạn yêu cầu đạo hàm cho (ví dụ: một vấn đề giá trị biên).


0

OK, tôi đã suy nghĩ một chút về nó và có lẽ tồn tại một thuật toán có thể theo dạng chung này:

Bạn cần tính toán bài toán nhân viên bán hàng du lịch cho biểu đồ 1000 nút, tuy nhiên, bạn cũng được cung cấp một danh sách các nút mà bạn không thể truy cập. Khi danh sách các nút không mong muốn phát triển lớn hơn, vấn đề trở nên dễ giải quyết hơn.


4
Đó là loại n khác trong O (n). Với thủ thuật này, bạn có thể nói mọi thuật toán đều có O (q) trong đó q là số người sống ở Trung Quốc chẳng hạn.
vava

2
Boyer-Moore thuộc loại tương tự (O (n / m)), nhưng điều đó không thực sự "tốt hơn O (1)", bởi vì n> = m. Tôi nghĩ điều tương tự cũng đúng với "TSP không mong muốn" của bạn.
Niki

Ngay cả trong trường hợp này, thời gian chạy của TSP là NP-Complete, bạn chỉ cần loại bỏ các nút khỏi biểu đồ và do đó giảm n hiệu quả.
Ed James

0

Tôi thấy một thuật toán được O (1 / n) thừa nhận ở giới hạn trên:

Bạn có một loạt lớn các đầu vào đang thay đổi do một thứ gì đó bên ngoài thói quen (có thể chúng phản ánh phần cứng hoặc thậm chí có thể là một số lõi khác trong bộ xử lý làm việc đó.) Và bạn phải chọn một đầu vào ngẫu nhiên nhưng hợp lệ.

Bây giờ, nếu nó không thay đổi, bạn chỉ cần tạo một danh sách các mục, chọn ngẫu nhiên một mục và nhận O (1) thời gian. Tuy nhiên, bản chất động của dữ liệu ngăn chặn việc lập danh sách, bạn chỉ cần thăm dò ngẫu nhiên và kiểm tra tính hợp lệ của đầu dò. (Và lưu ý rằng vốn dĩ không có gì đảm bảo câu trả lời vẫn còn hiệu lực khi được trả về. Điều này vẫn có thể sử dụng - giả sử, AI cho một đơn vị trong trò chơi. Nó có thể bắn vào mục tiêu bị khuất tầm nhìn trong khi nó bóp cò.)

Điều này có hiệu suất trường hợp xấu nhất là vô hạn nhưng hiệu suất trường hợp trung bình giảm khi không gian dữ liệu lấp đầy.


0

Trong phân tích số, các thuật toán gần đúng nên có độ phức tạp tiệm cận phụ không đổi trong dung sai xấp xỉ.

class Function
{
    public double[] ApproximateSolution(double tolerance)
    {
        // if this isn't sub-constant on the parameter, it's rather useless
    }
}

bạn thực sự có nghĩa là hằng số phụ, hoặc tuyến tính? Tại sao các thuật toán gần đúng nên là hằng số phụ? Và điều đó có nghĩa là gì ??
LarsH

@LarsH, sai số của thuật toán xấp xỉ tỷ lệ thuận với kích thước bước (hoặc với công suất dương của nó), do đó kích thước bước của bạn càng nhỏ, sai số càng nhỏ. Nhưng một cách phổ biến khác để kiểm tra một vấn đề gần đúng là lỗi so với số lần chia một khoảng thời gian. Số lượng phân vùng của một khoảng tỷ lệ nghịch với kích thước bước, do đó, tỷ lệ nghịch với một số công suất dương của số lượng phân vùng - khi bạn tăng số lượng phân vùng, lỗi của bạn sẽ giảm.
Andrew Lei

@AndrewLei: Wow, một câu trả lời gần 7 năm sau! Tôi hiểu câu trả lời của Sam bây giờ tốt hơn tôi đã làm. Cảm ơn vì đã phản hồi.
LarsH

0

Tôi đoán ít hơn O (1) là không thể. Bất kỳ thời gian nào của thuật toán được gọi là O (1). Nhưng đối với O (1 / n) thì làm thế nào về chức năng dưới đây. (Tôi biết có nhiều biến thể đã được trình bày trong giải pháp này, nhưng tôi đoán tất cả chúng đều có một số sai sót (không phải là chính, chúng giải thích khái niệm này tốt). Vì vậy, đây là một, chỉ để tranh luận:

def 1_by_n(n, C = 10):   #n could be float. C could be any positive number
  if n <= 0.0:           #If input is actually 0, infinite loop.
    while True:
      sleep(1)           #or pass
    return               #This line is not needed and is unreachable
  delta = 0.0001
  itr = delta
  while delta < C/n:
    itr += delta

Do đó, khi n tăng chức năng sẽ mất ít thời gian hơn. Ngoài ra, đảm bảo rằng nếu đầu vào thực sự là 0, thì hàm sẽ mất mãi mãi để trả về.

Người ta có thể lập luận rằng nó sẽ bị giới hạn bởi độ chính xác của máy. do đó, eit chân có giới hạn trên là O (1). Nhưng chúng ta cũng có thể bỏ qua điều đó bằng cách lấy đầu vào của n và C trong chuỗi. Và bổ sung và so sánh được thực hiện trên chuỗi. Ý tưởng là, với điều này, chúng ta có thể giảm n nhỏ tùy ý. Do đó, giới hạn trên của hàm không bị giới hạn, ngay cả khi chúng ta bỏ qua n = 0.

Tôi cũng tin rằng chúng ta không thể chỉ nói rằng thời gian chạy là O (1 / n). Nhưng chúng ta nên nói một cái gì đó như O (1 + 1 / n)


-1

Có thể xây dựng một thuật toán là O (1 / n). Một ví dụ sẽ là một vòng lặp lặp lại một số bội số của f (n) trong đó f (n) là một số hàm có giá trị được đảm bảo lớn hơn n và giới hạn của f (n) -n khi n tiến đến vô cùng là số không. Việc tính toán f (n) cũng cần phải là hằng số cho tất cả n. Tôi không biết f (n) sẽ trông như thế nào hoặc thuật toán như vậy sẽ có ứng dụng gì, theo tôi thì chức năng đó có thể tồn tại nhưng thuật toán kết quả sẽ không có mục đích nào khác ngoài việc chứng minh khả năng của thuật toán với O (1 / n).


Vòng lặp của bạn yêu cầu kiểm tra mất ít nhất thời gian không đổi, do đó thuật toán kết quả có độ phức tạp ít nhất là O (1).
Stefan Reich

-1

Tôi không biết về các thuật toán nhưng độ phức tạp nhỏ hơn O (1) xuất hiện trong các thuật toán ngẫu nhiên. Trên thực tế, o (1) (ít o) nhỏ hơn O (1). Loại phức tạp này thường xuất hiện trong các thuật toán ngẫu nhiên. Ví dụ, như bạn đã nói, khi xác suất của một số sự kiện là thứ tự 1 / n, chúng biểu thị nó bằng o (1). Hoặc khi họ muốn nói rằng một cái gì đó xảy ra với xác suất cao (ví dụ 1 - 1 / n) thì họ biểu thị nó bằng 1 - o (1).


-2

Nếu câu trả lời là như nhau bất kể dữ liệu đầu vào thì bạn có thuật toán O (0).

hay nói cách khác - câu trả lời được biết trước khi dữ liệu đầu vào được gửi - chức năng có thể được tối ưu hóa - vì vậy O (0)


Có thật không? Bạn vẫn sẽ cần trả về một giá trị, vì vậy nó vẫn không phải là O (1) chứ?
Joachim Sauer

7
không, O (0) có nghĩa là không mất thời gian cho tất cả các đầu vào. O (1) là thời gian không đổi.
Pete Kirkham

-2

Ký hiệu Big-O đại diện cho trường hợp xấu nhất đối với thuật toán không giống với thời gian chạy thông thường của nó. Thật đơn giản để chứng minh rằng thuật toán O (1 / n) là thuật toán O (1). Theo định nghĩa,
O (1 / n) -> T (n) <= 1 / n, với mọi n> = C> 0
O (1 / n) -> T (n) <= 1 / C, Vì 1 / n <= 1 / C với mọi n> = C
O (1 / n) -> O (1), vì ký hiệu Big-O bỏ qua các hằng số (tức là giá trị của C không quan trọng)


Không: Ký hiệu Big O cũng được sử dụng để nói về các tình huống trung bình và thời gian dự kiến ​​(và thậm chí là trường hợp tốt nhất). Phần còn lại sau.
Konrad Rudolph

Ký hiệu 'O' chắc chắn xác định giới hạn trên (về độ phức tạp thuật toán, đây sẽ là trường hợp xấu nhất). Omega và Theta được sử dụng để biểu thị trường hợp tốt nhất và trung bình, tương ứng.
Roland Ewald

2
Roland: Đó là một quan niệm sai lầm; giới hạn trên không giống với trường hợp xấu nhất, hai là hai khái niệm độc lập. Hãy xem xét thời gian chạy dự kiến ​​(và trung bình) của hashtable-containsthuật toán có thể được ký hiệu là O (1) - và trường hợp xấu nhất có thể được đưa ra rất chính xác là Theta (n)! Omega và Theta đơn giản có thể được sử dụng để biểu thị các giới hạn khác nhưng nói lại một lần nữa : chúng không liên quan gì đến trường hợp trung bình hoặc tốt nhất.
Konrad Rudolph

Konrad: Đúng. Tuy nhiên, Omega, Drama và O thường được sử dụng để thể hiện giới hạn và nếu tất cả các yếu tố đầu vào có thể được xem xét, O đại diện cho giới hạn trên, v.v.
Roland Ewald

1
Việc O (1 / n) là tập con của O (1) là tầm thường và theo trực tiếp từ định nghĩa. Trong thực tế, nếu một hàm g là O (h), thì bất kỳ hàm f nào là O (g) cũng là O (h).
Tobias

-2

Không có gì nhỏ hơn O (1) Ký hiệu Big-O ngụ ý thứ tự phức tạp lớn nhất cho một thuật toán

Nếu một thuật toán có thời gian chạy là n ^ 3 + n ^ 2 + n + 5 thì đó là O (n ^ 3) Các quyền hạn thấp hơn không quan trọng ở đây vì vì n -> Inf, n ^ 2 sẽ không liên quan so với 3 ^

Tương tự như n -> Inf, O (1 / n) sẽ không liên quan so với O (1) do đó 3 + O (1 / n) sẽ giống như O (1) do đó làm cho O (1) tính toán nhỏ nhất có thể phức tạp


-2
inline void O0Algorithm() {}

1
Đó sẽ là một thuật toán O (1).
Lasse V. Karlsen

2
Điều đó cũng tốt, nhưng vấn đề là nó không phải là Ω (1). Và tại sao câu trả lời của tôi bị đánh giá thấp? Nếu bạn nghĩ rằng tôi sai, làm thế nào để giải thích?
Stewart

Về cơ bản, tôi đã hỏi rằng câu trả lời này có chính xác hay không, và dường như nó đang bị tranh cãi: stackoverflow.com/questions/3209139/
Kẻ

Vâng, nó là nội tuyến, vì vậy bạn có thể xem xét nó O (0). Tuy nhiên, tất cả các thuật toán O (0) là tầm thường (không làm gì), vì vậy ... không phải là một câu trả lời rất thú vị.
Stefan Reich

@StefanReich Đúng, đó không phải là một câu trả lời rất thú vị, nhưng đó là một câu trả lời.
Stewart

-2

Đây là một thuật toán O (1 / n) đơn giản. Và nó thậm chí còn làm một cái gì đó thú vị!

function foo(list input) {
  int m;
  double output;

  m = (1/ input.size) * max_value;  
  output = 0;
  for (int i = 0; i < m; i++)
    output+= random(0,1);

  return output;
}

O (1 / n) là có thể vì nó mô tả cách đầu ra của hàm thay đổi khi tăng kích thước đầu vào. Nếu chúng ta đang sử dụng hàm 1 / n để mô tả số lượng lệnh mà hàm thực thi thì không có yêu cầu nào hàm đó thực hiện các lệnh không cho bất kỳ kích thước đầu vào nào. Thay vào đó, với mỗi kích thước đầu vào, n trên một số ngưỡng, số lượng lệnh được yêu cầu được giới hạn ở trên bởi một hằng số dương nhân với 1 / n. Vì không có số thực tế trong đó 1 / n là 0 và hằng số là dương, nên không có lý do gì mà hàm sẽ bị hạn chế thực hiện 0 hoặc ít hơn các hướng dẫn.


1
Vì O (1 / n) sẽ nằm dưới đường ngang = 1 và khi n đạt vô hạn, mã của bạn vẫn sẽ thực hiện một số bước nhất định, thuật toán này là thuật toán O (1). Ký hiệu Big-O là một hàm của tất cả các phần khác nhau của thuật toán và nó chọn phần lớn nhất. Vì phương thức sẽ luôn chạy một số hướng dẫn, khi n đạt đến vô hạn, bạn sẽ để lại cùng các hướng dẫn đó thực thi mỗi lần, và do đó phương thức sẽ chạy trong thời gian không đổi. Cấp, nó sẽ không có nhiều thời gian, nhưng điều đó không liên quan đến ký hiệu Big-O.
Lasse V. Karlsen
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.