Các thuật toán trong thế giới thực có vượt trội hơn rất nhiều trong lớp bên dưới không? [đóng cửa]


39

Đêm qua tôi đã thảo luận với một lập trình viên khác rằng mặc dù có thể là O (1), một hoạt động là O (n) có thể vượt trội hơn nếu có một hằng số lớn trong thuật toán O (1). Anh ấy không đồng ý, vì vậy tôi đã mang nó đến đây.

Có ví dụ nào về các thuật toán vượt trội hơn nhiều so với các thuật toán trong lớp bên dưới nó không? Ví dụ: O (n) nhanh hơn O (1) hoặc O (n 2 ) nhanh hơn O (n).

Về mặt toán học, điều này có thể được chứng minh cho một hàm có giới hạn trên không có triệu chứng, khi bạn bỏ qua các yếu tố không đổi, nhưng các thuật toán như vậy có tồn tại trong tự nhiên không? Và tôi sẽ tìm thấy những ví dụ về chúng ở đâu? Những loại tình huống họ được sử dụng cho?


15
Ngay cả đối với các thuật toán "lớn", nhỏ hơn không nhất thiết phải tốt hơn. Ví dụ, loại bỏ gaussian là O (n ^ 3), nhưng có những thuật toán có thể thực hiện được trong O (n ^ 2), nhưng hệ số của thuật toán thời gian bậc hai rất lớn đến nỗi mọi người chỉ đi với O (n ^ 3) một.
BlackJack

11
Bạn phải thêm "... cho các vấn đề trong thế giới thực" hoặc một số vấn đề khác để biến điều này thành một câu hỏi hợp lý. Nếu không, bạn chỉ cần làm cho nđủ lớn để bù cho hằng số (đó là điểm của ký hiệu big-O).
starblue

8
Đừng lấy ký hiệu big-O cho tốc độ.
Codism

16
Điểm của ký hiệu big-O không phải là cho bạn biết thuật toán chạy nhanh như thế nào, mà là nó có tỷ lệ tốt như thế nào.
BlueRaja - Daniel Pflughoeft

4
Tôi ngạc nhiên không ai đề cập đến thuật toán Simplex để giải LP. Nó có một trường hợp xấu nhất theo cấp số nhân với thời gian chạy tuyến tính dự kiến. Trong thực tế, nó khá nhanh. Thật là tầm thường khi xây dựng một vấn đề thể hiện thời gian chạy trong trường hợp xấu nhất. Ngoài ra, nó được sử dụng rất nhiều.
ccoakley

Câu trả lời:


45

Tra cứu trong các bảng dữ liệu cố định rất nhỏ. Bảng băm được tối ưu hóa có thể là O (1) và chậm hơn so với tìm kiếm nhị phân hoặc thậm chí là tìm kiếm tuyến tính do chi phí tính toán băm.


14
Chính xác hơn, tra cứu hashtable là O (m) trong đó m là kích thước của khóa. Bạn chỉ có thể gọi O (1) nếu kích thước khóa không đổi. Ngoài ra, thường là khấu hao - nếu không, bảng không thể tăng / thu hẹp. Cây ternary thường có thể đánh bại các bảng băm để tìm kiếm chuỗi trong bối cảnh nơi các chuỗi thường không được tìm thấy - tìm kiếm cây ternary thường sẽ phát hiện ra rằng khóa không xuất hiện trong khi vẫn kiểm tra ký tự đầu tiên hoặc hai của chuỗi, trong đó phiên bản hashtable chưa tính băm.
Steve314

2
Tôi yêu câu trả lời của Loren Pechtel và bình luận đầu tiên của Steve314. Tôi thực sự đã thấy điều này xảy ra. Nếu bạn tạo một lớp Java có phương thức hashcode () mất quá nhiều thời gian để trả về giá trị băm (và không / không thể lưu trữ nó), thì hãy sử dụng các thể hiện của một lớp như vậy trong bộ sưu tập kiểu băm (như Hashset) sẽ làm cho bộ sưu tập đó ALOT chậm hơn bộ sưu tập kiểu mảng (như ArrayList).
Rồng Shivan

1
@ Steve314: tại sao bạn giả sử các hàm băm là O (m) trong đó m là kích thước của khóa? Các hàm băm có thể là O (1) ngay cả khi bạn đang xử lý các chuỗi (hoặc loại phức tạp khác). Không có quá nhiều giá trị để đặt nó theo định nghĩa chính thức hơn là việc nhận ra hàm băm có thể thay đổi đáng kể độ phức tạp nếu cấu trúc dữ liệu sai (bảng băm) được chọn cho đầu vào của bạn (kích thước khóa là không thể đoán trước).
Codism

1
@ Steve314: Lưu ý rằng tôi đã nói bảng dữ liệu cố định. Chúng không phát triển. Ngoài ra, bạn chỉ nhận được hiệu suất O (1) từ bảng băm nếu bạn có thể tối ưu hóa khóa để đảm bảo không có xung đột.
Loren Pechtel

1
@Loren - Nghiêm túc, nếu bảng có kích thước cố định, sẽ có một lượng thời gian tối đa không đổi mà bạn có thể dành để tìm kiếm một không gian trống. Đó là, nhiều nhất, bạn có thể cần kiểm tra các vị trí đã điền n-1 trong đó n là kích thước bảng không đổi. Vì vậy, bảng băm có kích thước cố định thực sự là O (1), không cần phân tích khấu hao. Điều này không có nghĩa là bạn không quan tâm đến việc truy cập trở nên chậm hơn khi bảng đầy - chỉ có điều đó không phải là những gì O lớn thể hiện.
Steve314

25

Phép nhân ma trận. Thuật toán O (n ^ 3) ngây thơ thường được sử dụng trong thực tế nhanh hơn so với Strassen's O (n ^ 2.8) cho các ma trận nhỏ; và Strassen's được sử dụng thay cho thuật toán O (n ^ 2.3) của Coppersmith đối với các ma trận lớn hơn.



2
Coppersmith-Winograd KHÔNG BAO GIỜ được sử dụng. Thực hiện nó sẽ là một nhiệm vụ khủng khiếp trong chính nó và hằng số là rất tệ, nó sẽ không khả thi ngay cả đối với các vấn đề ma trận khoa học hiện đại.
tskuzzy

24

Một ví dụ đơn giản là sự khác biệt giữa các thuật toán sắp xếp khác nhau. Hợp nhất, Heapsort và một số khác là O (n log n) . Quicksort là trường hợp xấu nhất O (n ^ 2) . Nhưng thường Quicksort nhanh hơn và trên thực tế, nó hoạt động trung bình như O (n log n) . Thêm thông tin .

Một ví dụ khác là việc tạo ra một số Fibonacci duy nhất. Thuật toán lặp là O (n) , trong khi thuật toán dựa trên ma trận là O (log n) . Tuy nhiên, đối với vài nghìn số Fibonacci đầu tiên, thuật toán lặp có thể nhanh hơn. Điều này cũng phụ thuộc vào việc thực hiện khóa học!

Các thuật toán có hiệu suất tiệm cận tốt hơn có thể chứa các hoạt động tốn kém không cần thiết với thuật toán có hiệu suất kém hơn nhưng hoạt động đơn giản hơn. Cuối cùng, chú thích O chỉ cho chúng ta biết điều gì đó về hiệu suất khi đối số mà nó hoạt động tăng lên đáng kể (tiếp cận vô hạn).


Đây là một lời giải thích tuyệt vời về Big-O, nhưng không giải quyết được phần cốt lõi của câu hỏi, dành cho các trường hợp cụ thể trong đó thuật toán O (n) sẽ nhanh hơn O (1).
KyleWpppd

Số một Fibonacci là hơi tắt. Kích thước đầu ra là số mũ trong kích thước đầu vào, do đó, đây là sự khác biệt giữa O (lg n * e ^ n) so với O (lg lg n * e ^ n).
Peter Taylor

Phụ lục: tốt nhất. Thuật toán dựa trên ma trận thực hiện phép nhân với các số theo thứ tự 1,5 ^ n, vì vậy O (lg lg n * ne ^ n) có thể là chứng minh ràng buộc tốt nhất.
Peter Taylor

1
Quicksort thường được mô tả là hiệu suất mong đợi O (n log n) - trường hợp xấu nhất rất khó xảy ra đối với các đầu vào ngẫu nhiên và xây dựng một số ngẫu nhiên thành một lựa chọn hoặc vào lựa chọn trục có nghĩa là trường hợp xấu nhất rất khó xảy ra đối với các kích cỡ đầu vào quan trọng. Trường hợp xấu nhất ít liên quan hơn thực tế là quicksort rất đơn giản và (2) rất thân thiện với bộ nhớ cache, cả hai đều dẫn đến các yếu tố không đổi tốt hơn đáng kể so với nhiều thuật toán sắp xếp khác.
Steve314

(2) chính xác là loại xem xét bên ngoài phải được tính đến khi xem xét hiệu suất big-O. Về mặt thuật toán, Mergesort phải luôn vượt trội so với Quicksort, nhưng việc sử dụng tài nguyên và cục bộ bộ đệm thường đảo ngược các vị trí hiệu suất trong thế giới thực của chúng.
Dan Lyons

18

Lưu ý: Vui lòng đọc các bình luận của @ back2dos bên dưới và các bậc thầy khác, vì thực tế chúng hữu ích hơn những gì tôi đã viết - Cảm ơn tất cả những người đóng góp.

Tôi nghĩ từ biểu đồ bên dưới (lấy từ: Ký hiệu Big O , tìm kiếm "Bản chất bi quan của thuật toán:"), bạn có thể thấy rằng O (log n) không phải lúc nào cũng tốt hơn nói, O (n). Vì vậy, tôi đoán lập luận của bạn là hợp lệ.

Ảnh-1


6
Câu hỏi muốn các ví dụ cụ thể trong thế giới thực của các thuật toán. Điều này không có bất kỳ như nó đứng.
Megan Walker

19
Bạn có thể thấy không có gì trên biểu đồ đó, điều đó sẽ trả lời câu hỏi. Đó là sự hiểu lầm. Biểu đồ này chỉ vẽ đồ thị của các hàm y = 1, y = log xvân vân và giao điểm của y = 1y = xthực sự là điểm (1,1). Nếu điều này thực sự chính xác, hơn nó sẽ cho bạn biết, các thuật toán có độ phức tạp cao hơn có thể nhanh hơn cho 0 đến 2 mục, đây là điều mà mọi người khó có thể quan tâm. Những gì biểu đồ hoàn toàn không tính đến (và sự khác biệt hiệu suất có thể nhận thấy trong câu hỏi đến từ đâu) là các yếu tố không đổi.
back2dos

@Samuel Walker, cảm ơn vì nhận xét. Liên kết được cung cấp (Liên kết-1) có một số ví dụ về thuật toán cho mỗi danh mục.
NoChance

5
@ back2dos: Đồ thị trên chính nó không trả lời câu hỏi, nhưng có thể được sử dụng để trả lời nó. Hình dạng của mỗi chức năng được hiển thị là giống nhau cho bất kỳ tỷ lệ và hệ số không đổi. Với biểu đồ này cho thấy sự kết hợp của các hàm đã cho, có một phạm vi đầu vào mà cái nào nhỏ hơn và phạm vi đầu vào mà cái kia là.
Jan Hudec

2
@dan_waterworth, bạn nói đúng, tôi sẽ thừa nhận quan điểm đó và xóa nhận xét đó. Tuy nhiên, câu trả lời là không chính xác hoặc sai lệch ở hai khía cạnh: 1) Toàn bộ quan điểm của Big-O là nó đưa ra giới hạn trên về độ phức tạp; nó chỉ có ý nghĩa đối với n lớn bởi vì chúng tôi rõ ràng đưa ra các thuật ngữ nhỏ hơn bị áp đảo bởi thuật ngữ lớn nhất khi n phát triển. 2) Điểm của câu hỏi là tìm các ví dụ về hai thuật toán trong đó thuật toán có ràng buộc Big-O cao hơn vượt trội so với thuật toán có giới hạn thấp hơn. Câu trả lời này không thành công vì nó không đưa ra bất kỳ ví dụ nào như vậy.
Caleb

11

Đối với các giá trị thực tế của n, có. Điều này xuất hiện rất nhiều trong lý thuyết CS. Thường có một thuật toán phức tạp có hiệu suất lớn hơn về mặt kỹ thuật, nhưng các yếu tố không đổi quá lớn để làm cho nó không thực tế.

Tôi đã từng có giáo sư hình học tính toán của mình mô tả một thuật toán để tam giác một đa giác trong thời gian tuyến tính, nhưng ông đã hoàn thành với "rất phức tạp. Tôi không nghĩ có ai thực sự thực hiện nó" (!!).

Ngoài ra, đống heap của Wikipedia có các đặc điểm tốt hơn so với đống thông thường, nhưng không phổ biến lắm vì chúng không hoạt động tốt trong thực tế như các đống thông thường. Điều này có thể xếp tầng cho các thuật toán khác sử dụng heaps - ví dụ, các đường đi ngắn nhất của Dijkstra nhanh hơn về mặt toán học với một heap của Wikipedia, nhưng thường không có trong thực tế.


Nó nhanh hơn cho các đồ thị khổng lồ theo thứ tự 100.000 hoặc hơn các đỉnh.
tskuzzy

Các đống Fibonacci là suy nghĩ đầu tiên (thực sự, thứ hai) của tôi là tốt.
Konrad Rudolph

10

So sánh chèn vào danh sách liên kết và chèn vào một mảng có thể thay đổi kích thước.

Lượng dữ liệu phải khá lớn để chèn danh sách O (1) được liên kết có giá trị.

Một danh sách liên kết có thêm chi phí cho con trỏ và hội nghị tiếp theo. Một mảng có thể thay đổi kích thước phải sao chép dữ liệu xung quanh. Sao chép đó là O (n), nhưng trong thực tế rất nhanh.


1
Một mảng có thể thay đổi kích thước được nhân đôi kích thước mỗi lần nó lấp đầy, do đó, chi phí thay đổi kích thước trung bình cho mỗi lần chèn là O (1).
kevin cline

2
@kevincline, có nhưng O (n) xuất phát từ việc phải di chuyển tất cả các yếu tố sau khi chèn điểm về phía trước. Phân bổ được khấu hao O (1) thời gian. Quan điểm của tôi là chuyển động đó vẫn rất nhanh, vì vậy trong thực tế thường là nhịp đập các danh sách liên kết.
Winston Ewert

Lý do các mảng liền kề quá nhanh so với các danh sách được liên kết là do bộ nhớ đệm của bộ xử lý. Truy cập danh sách được liên kết sẽ gây ra lỗi nhớ cache cho mọi thành phần. Để có được điều tốt nhất của cả hai thế giới, bạn nên sử dụng một danh sách liên kết không được kiểm soát .
dan_waterworth

Mảng có thể thay đổi kích thước không phải lúc nào cũng sao chép. Nó phụ thuộc vào những gì nó đang chạy và nếu có bất cứ điều gì cản trở. Tương tự cho kích thước nhân đôi, thực hiện cụ thể. Việc cuộn qua cuộn mặc dù là một vấn đề. Danh sách được liên kết thường là tốt nhất cho hàng đợi có kích thước không xác định mặc dù bộ đệm quay cho hàng đợi chạy theo tiền của họ. Trong các trường hợp khác, danh sách được liên kết là hữu ích vì phân bổ hoặc mở rộng đơn giản là sẽ không cho phép bạn có những thứ liên tục mọi lúc nên bạn sẽ cần một con trỏ.
jgmjgm

@jgmjgm, nếu bạn chèn vào giữa một mảng có thể thay đổi kích thước, nó hoàn toàn không sao chép các phần tử sau đó.
Winston Ewert

8

Ký hiệu Big-Oh được sử dụng để mô tả tốc độ tăng trưởng của hàm, do đó, có thể thuật toán O (1) sẽ nhanh hơn, nhưng chỉ đến một điểm nhất định (hệ số không đổi).

Các ký hiệu phổ biến:

O (1) - Số lần lặp (đôi khi bạn có thể gọi đây là thời gian người dùng dành cho chức năng) không phụ thuộc vào kích thước của đầu vào và trên thực tế là không đổi.

O (n) - Số lần lặp tăng theo tỷ lệ tuyến tính với kích thước của đầu vào. Ý nghĩa - nếu thuật toán lặp qua bất kỳ lần nhập N, 2 * N nào, thì nó vẫn được coi là O (n).

O (n ^ 2) (bậc hai) - Số lần lặp là kích thước đầu vào bình phương.


2
Để thêm một ví dụ cho một câu trả lời xuất sắc khác: phương pháp O (1) có thể mất 37 năm cho mỗi cuộc gọi, trong khi phương thức O (n) có thể mất 16 * n micro giây cho mỗi cuộc gọi. Cái nào nhanh hơn?
Kaz Dragon

16
Tôi hoàn toàn không thấy cách này trả lời câu hỏi.
avakar

7
Tôi hiểu lớn-O. Điều này không giải quyết câu hỏi thực tế, đó là ví dụ cụ thể về các hàm trong đó các thuật toán có chữ O lớn thấp hơn vượt trội so với câu hỏi có chữ O lớn hơn.
KyleWpppd

Khi bạn đặt câu hỏi ở dạng "Có ví dụ ...", chắc chắn ai đó sẽ trả lời "Có". mà không đưa ra bất kỳ.
rakslice

1
@rakslice: Có lẽ vậy. Tuy nhiên trang web này yêu cầu giải thích (hoặc tốt hơn bằng chứng) về bất kỳ tuyên bố nào bạn đưa ra. Bây giờ cách tốt nhất để chứng minh, có những ví dụ như vậy là đưa ra một;)
back2dos

6

Các thư viện Regex thường được triển khai để thực hiện quay lui trong trường hợp xấu nhất theo thời gian theo cấp số nhân thay vì tạo ra DFA có độ phức tạp O(nm).

Quay lui ngây thơ có thể là một hoạt động tốt hơn khi đầu vào vẫn ở trên đường nhanh hoặc thất bại mà không cần phải quay lại quá mức.

(Mặc dù quyết định này không chỉ dựa trên hiệu suất, mà còn cho phép tham chiếu lại.)


Tôi nghĩ đó cũng là một phần lịch sử - thuật toán biến biểu thức chính quy thành DFA đã được cấp bằng sáng chế khi một số công cụ trước đó (sed và grep, tôi đoán vậy) đang được phát triển. Tất nhiên tôi đã nghe điều này từ giáo sư biên dịch của tôi, người không hoàn toàn chắc chắn, vì vậy đây là tài khoản cũ.
Tikhon Jelvis

5

Một O(1)thuật toán:

def constant_time_algorithm
  one_million = 1000 * 1000
  sleep(one_million) # seconds
end

Một O(n)thuật toán:

def linear_time_algorithm(n)
  sleep(n) # seconds
end

Rõ ràng, đối với bất kỳ giá trị của nnơi n < one_million, các O(n)thuật toán được đưa ra trong ví dụ sẽ nhanh hơn so với O(1)thuật toán.

Mặc dù ví dụ này hơi phức tạp, nhưng nó tương đương với tinh thần của ví dụ sau:

def constant_time_algorithm
  do_a_truckload_of_work_that_takes_forever_and_a_day
end

def linear_time_algorithm(n)
  i = 0
  while i < n
    i += 1
    do_a_minute_amount_of_work_that_takes_nanoseconds
  end
end

Bạn phải biết các hằng số và hệ số trong Obiểu thức của mình và bạn phải biết phạm vi dự kiến n, để xác định tiên nghiệm thuật toán nào sẽ kết thúc nhanh hơn.

Mặt khác, bạn phải điểm chuẩn hai thuật toán với các giá trị ntrong phạm vi dự kiến ​​để xác định một posteriori mà thuật toán kết thúc nhanh hơn.


4

Sắp xếp

Sắp xếp chèn là O (n ^ 2) nhưng vượt trội hơn các thuật toán sắp xếp O (n * log (n)) khác cho số lượng nhỏ các phần tử.

Đây là lý do tại sao hầu hết các triển khai sắp xếp sử dụng kết hợp hai thuật toán. Ví dụ: sử dụng sắp xếp hợp nhất để phá vỡ các mảng lớn cho đến khi chúng đạt đến một mảng có kích thước nhất định, sau đó sử dụng sắp xếp chèn để sắp xếp các đơn vị nhỏ hơn và hợp nhất lại với sắp xếp hợp nhất.

Xem Timsort triển khai mặc định hiện tại của Python và Java 7 sắp xếp sử dụng kỹ thuật này.



3

Bubbledort trong bộ nhớ có thể vượt trội so với quicksort khi chương trình được hoán đổi sang đĩa hoặc cần đọc mọi mục từ đĩa khi so sánh.

Đây phải là một ví dụ anh ta có thể liên quan đến.


Không phải sự phức tạp được trích dẫn trên quicksort và bubbleort cho rằng truy cập bộ nhớ ngẫu nhiên O (1) sao? Nếu đây không còn là trường hợp nữa, thì sự phức tạp của quicksorts có cần phải được xem xét lại không?
Viktor Dahl

@ViktorDahl, thời gian truy cập mục không phải là một phần của truyền thống được đo lường theo độ phức tạp thuật toán sắp xếp nên "O (1)" không phải là lựa chọn từ đúng ở đây. Sử dụng "thời gian không đổi" thay thế. PHK đã viết một bài báo trước đây về các thuật toán sắp xếp khi biết rằng một số mặt hàng đắt hơn để truy xuất so với các thuật toán khác (bộ nhớ ảo) - queue.acm.org/detail.cfm?id=1814327 - bạn có thể thấy nó thú vị.

Tôi thấy lỗi của tôi bây giờ. Người ta thường đo số lượng so sánh, và tất nhiên chúng không bị ảnh hưởng bởi tốc độ của phương tiện lưu trữ. Ngoài ra, cảm ơn cho các liên kết.
Viktor Dahl

3

Thông thường các thuật toán tiên tiến hơn giả định một số lượng thiết lập (đắt tiền) nhất định. Nếu bạn chỉ cần chạy nó một lần, bạn có thể tốt hơn với phương pháp brute-force.

Ví dụ: tìm kiếm nhị phân và tra cứu bảng băm đều nhanh hơn nhiều cho mỗi lần tra cứu sau đó là tìm kiếm tuyến tính, nhưng chúng yêu cầu bạn sắp xếp danh sách hoặc xây dựng bảng băm tương ứng.

Việc sắp xếp sẽ khiến bạn mất N log (N) và bảng băm sẽ có giá ít nhất là N. Bây giờ nếu bạn đang thực hiện hàng trăm hoặc hàng nghìn lượt tra cứu, đó vẫn là một khoản tiết kiệm được khấu hao. Nhưng nếu bạn chỉ cần thực hiện một hoặc hai lần tra cứu, có thể chỉ cần thực hiện tìm kiếm tuyến tính và tiết kiệm chi phí khởi động.


1

Giải mã thường là 0 (1). Ví dụ, không gian khóa cho DES là 2 ^ 56, vì vậy việc giải mã bất kỳ tin nhắn nào là hoạt động theo thời gian không đổi. Chỉ là bạn có hệ số 2 ^ 56 trong đó nên hằng số thực sự lớn.


Không giải mã được tin nhắn O ( n ), trong đó n tỷ lệ thuận với kích thước của tin nhắn? Miễn là bạn có khóa chính xác, kích thước của khóa thậm chí không được xem xét; một số thuật toán có các quy trình thiết lập / mở rộng khóa tối thiểu hoặc không có (DES, RSA - lưu ý rằng việc tạo khóa vẫn có thể là một nhiệm vụ phức tạp, nhưng không liên quan gì đến việc mở rộng khóa) trong khi các thuật toán khác cực kỳ phức tạp (Thổi vào tâm trí), nhưng Khi đã xong, thời gian để thực hiện công việc thực tế tỷ lệ thuận với kích thước của tin nhắn, do đó O (n).
một CVn

Bạn có thể có nghĩa là tiền điện tử hơn là giải mã?
leftaroundabout

3
Vâng, vâng, có bất kỳ số lượng nào mà bạn có thể lấy là hằng số và khai báo một thuật toán là O (1). [sắp xếp giả định các phần tử mất một lượng thời gian không đổi để so sánh, ví dụ, hoặc bất kỳ phép toán nào với các số không phải là bignum]
Random832

1

Thực hiện khác nhau của bộ mùa xuân đến tâm trí của tôi. Một trong những ngây thơ nhất đang triển khai nó trên một vector, mà phương tiện removecũng như containsvà do đó cũng addtất cả mất O (N).
Một cách khác là triển khai nó trên một số hàm băm mục đích chung, ánh xạ băm đầu vào thành các giá trị đầu vào. Việc thực hiện bộ Thực hiện như vậy với O (1) cho add, containsremove.

Nếu chúng ta giả sử N là khoảng 10 hoặc hơn, thì việc thực hiện đầu tiên có thể nhanh hơn. Tất cả những gì phải làm để tìm một phần tử là so sánh 10 giá trị với một giá trị.
Việc thực hiện khác sẽ phải bắt đầu tất cả các loại biến đổi thông minh, có thể tốn kém hơn rất nhiều, so với việc thực hiện 10 so sánh. Với tất cả chi phí hoạt động, bạn thậm chí có thể bị mất bộ nhớ cache và về lý thuyết giải pháp của bạn nhanh đến mức nào.

Điều này không có nghĩa là việc triển khai tồi tệ nhất mà bạn có thể nghĩ sẽ vượt trội hơn so với việc thực hiện tốt, nếu N đủ nhỏ. Nó đơn giản có nghĩa là đối với N đủ nhỏ, rằng một triển khai ngây thơ, với dấu chân và chi phí thấp thực sự có thể yêu cầu ít hướng dẫn hơn và gây ra lỗi nhớ cache ít hơn so với triển khai đặt khả năng mở rộng trước, và do đó sẽ nhanh hơn.

Bạn thực sự không thể biết mọi thứ diễn ra nhanh như thế nào trong một kịch bản trong thế giới thực, cho đến khi bạn đặt nó thành một và chỉ cần đo nó. Thường thì kết quả rất đáng ngạc nhiên (ít nhất là với tôi).


1

Có, đối với nhỏ thích hợp N. Sẽ luôn có N, ở trên đó bạn sẽ luôn có thứ tự O (1) <O (lg N) <O (N) <O (N log N) <O (N ^ c ) <O (c ^ N) (trong đó O (1) <O (lg N) có nghĩa là tại thuật toán O (1) sẽ thực hiện ít thao tác hơn khi N lớn phù hợp và c là hằng số cố định lớn hơn 1 ).

Nói một thuật toán O (1) cụ thể thực hiện chính xác các hoạt động f (N) = 10 ^ 100 (một googol) và thuật toán O (N) thực hiện chính xác các hoạt động g (N) = 2 N + 5. Thuật toán O (N) sẽ cho hiệu năng cao hơn cho đến khi bạn N gần như là một googol (thực tế là khi N> (10 ^ 100 - 5) / 2), vì vậy nếu bạn chỉ mong N sẽ ở trong phạm vi 1000 đến một tỷ bạn sẽ phải chịu một hình phạt lớn khi sử dụng thuật toán O (1).

Hoặc để so sánh thực tế, giả sử bạn đang nhân các số có n chữ số với nhau. Các thuật toán Karatsuba là tối đa 3 n ^ (lg 3) hoạt động (có nghĩa là khoảng O (n ^ 1,585)) trong khi thuật toán Schönhage-Strassen là O (N log N log log N) mà là một trật tự nhanh hơn , nhưng để trích dẫn wikipedia:

Trong thực tế, thuật toán Schönhage bụi Strassen bắt đầu vượt trội so với các phương pháp cũ hơn như phép nhân Karatsuba và ToomTHER Cook cho các số vượt quá 2 ^ 2 ^ 15 đến 2 ^ 2 ^ 17 (10.000 đến 40.000 chữ số thập phân). [4] [5] [6] ]

Vì vậy, nếu bạn nhân các số có 500 chữ số với nhau, sẽ không có nghĩa khi sử dụng thuật toán "nhanh hơn" bằng các đối số O lớn.

EDIT: Bạn có thể tìm thấy xác định f (N) so với g (N), bằng cách lấy giới hạn N-> vô cùng của f (N) / g (N). Nếu giới hạn là 0 thì f (N) <g (N), nếu giới hạn là vô cùng thì f (N)> g (N) và nếu giới hạn là một hằng số khác thì f (N) ~ g (N) về mặt ký hiệu O lớn.


1

Phương pháp đơn giản cho lập trình tuyến tính có thể theo cấp số nhân trong trường hợp xấu nhất, trong khi các thuật toán điểm bên trong tương đối mới có thể là đa thức.

Tuy nhiên, trong thực tế, trường hợp xấu nhất theo cấp số nhân của phương pháp đơn giản không xuất hiện - phương pháp đơn giản là nhanh và đáng tin cậy, trong khi các thuật toán điểm nội thất ban đầu quá chậm để có thể cạnh tranh. (Hiện nay có các thuật toán điểm nội thất hiện đại hơn khả năng cạnh tranh - nhưng phương pháp đơn giản là ...)


0

Thuật toán của Ukkonen để xây dựng hậu tố thử là O (n log n). Nó có lợi thế là "trực tuyến" - nghĩa là, bạn có thể tăng thêm văn bản.

Gần đây, các thuật toán phức tạp khác đã tuyên bố là nhanh hơn trong thực tế, phần lớn là do truy cập bộ nhớ của chúng có tính cục bộ cao hơn, do đó cải thiện việc sử dụng bộ đệm của bộ xử lý và tránh các quầy hàng của CPU. Xem, ví dụ, khảo sát này , tuyên bố rằng 70-80% thời gian xử lý được dành để chờ bộ nhớ và bài viết này mô tả thuật toán "wotd".

Suffix cố gắng rất quan trọng trong di truyền học (để phù hợp với trình tự gen) và, phần nào ít quan trọng hơn trong việc thực hiện từ điển Scrabble.


0

Luôn có thuật toán nhanh nhất và nhanh nhất cho mọi vấn đề được xác định rõ . Về mặt lý thuyết, đây chỉ là thuật toán nhanh nhất (không có triệu chứng).

Với bất kỳ mô tả của một vấn đề P và một ví dụ cho rằng vấn đề tôi , nó liệt kê tất cả các thuật toán có thể Một và chứng minh Pr , kiểm tra cho mỗi cặp như vậy cho dù Pr là một bằng chứng hợp lệ mà A là thuật toán tiệm cận nhanh nhất cho P . Nếu nó tìm thấy một bằng chứng như vậy, nó sau đó thực hiện một trên tôi .

Tìm kiếm cặp chứng minh vấn đề này có độ phức tạp O (1) (đối với một vấn đề cố định P ), vì vậy bạn luôn sử dụng thuật toán nhanh nhất không có triệu chứng cho vấn đề. Tuy nhiên, vì hằng số này rất lớn trong hầu hết các trường hợp, nên phương pháp này hoàn toàn vô dụng trong thực tế.


0

Nhiều ngôn ngữ / khung sử dụng khớp mẫu ngây thơ để khớp chuỗi thay vì KMP . Chúng tôi tìm kiếm chuỗi như Tom, New York chứ không phải ababaabababababababababababab.

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.