Thời gian không đổi và thời gian liên tục được khấu hao có hiệu quả được coi là tương đương không?


16

Tôi cần phải viết RandomQueue cho phép nối thêm và xóa ngẫu nhiên trong Thời gian không đổi (O (1)).

Suy nghĩ đầu tiên của tôi là sao lưu nó với một số loại Array (tôi đã chọn một ArrayList), vì các mảng có quyền truy cập liên tục thông qua một chỉ mục.

Nhìn qua tài liệu mặc dù, tôi nhận ra rằng các bổ sung của ArrayLists được coi là Thời gian không đổi được khấu hao, vì một bổ sung có thể yêu cầu phân bổ lại mảng bên dưới, đó là O (n).

Là thời gian liên tục được khấu hao và thời gian không đổi có hiệu quả như nhau hay tôi cần xem xét một số cấu trúc thay thế không yêu cầu phân bổ lại đầy đủ cho mỗi lần bổ sung?

Tôi đang hỏi điều này bởi vì các cấu trúc dựa trên mảng sang một bên (mà theo như tôi biết sẽ luôn có các bổ sung Thời gian không đổi được khấu hao), tôi không thể nghĩ ra bất cứ điều gì sẽ đáp ứng các yêu cầu:

  • Bất cứ thứ gì dựa trên cây sẽ có quyền truy cập O (log n) tốt nhất
  • Một danh sách được liên kết có khả năng có thể có các bổ sung O (1) (nếu tham chiếu đến đuôi được giữ), nhưng loại bỏ ngẫu nhiên nên ở mức tốt nhất là O (n).

Đây là câu hỏi đầy đủ; trong trường hợp tôi dán mắt vào một số chi tiết quan trọng:

Thiết kế và triển khai RandomQueue. Đây là một triển khai của giao diện Hàng đợi trong đó thao tác remove () loại bỏ một phần tử được chọn ngẫu nhiên trong số tất cả các phần tử hiện có trong hàng đợi. .


Việc chuyển nhượng chỉ định cách loại bỏ ngẫu nhiên được thực hiện? Bạn có được cung cấp một chỉ mục để loại bỏ hoặc tham chiếu đến một yếu tố hàng đợi?

Nó không cung cấp bất kỳ chi tiết cụ thể. Các yêu cầu chỉ là một cấu trúc thực hiện giao diện Hàng đợi và có các bổ sung và loại bỏ O (1).
Carcigenicate

Như một bên - một mảng có thể thay đổi được với O (n) đang phát triển không nhất thiết phải có thêm O (1): điều này phụ thuộc vào cách chúng ta phát triển mảng. Tăng thêm một lượng không đổi a vẫn là O (n) để thêm vào (chúng ta có 1/acơ hội cho hoạt động O (n)), nhưng tăng trưởng theo hệ số không đổi a > 1là O (1) được khấu hao để thêm vào: chúng ta có (1/a)^ncơ hội O (n) hoạt động, nhưng xác suất đó gần bằng không n.
amon

ArrayLists sử dụng đúng sau?
Carcigenicate

1
Tác giả của câu hỏi (tôi) đã nghĩ đến giải pháp thời gian không đổi được khấu hao. Tôi sẽ làm rõ điều đó trong phiên bản tiếp theo. (Mặc dù trường hợp xấu nhất có thể đạt được thời gian liên tục ở đây bằng cách sử dụng kỹ thuật khử khấu hao .)
Pat Morin

Câu trả lời:


10

Thời gian liên tục được khấu hao hầu như luôn có thể được coi là tương đương với Thời gian liên tục và không cần biết chi tiết cụ thể về ứng dụng của bạn và loại sử dụng mà bạn dự định thực hiện cho hàng đợi này, rất có thể bạn sẽ được bảo hiểm.

Một danh sách mảng có khái niệm về công suất , về cơ bản bằng với kích thước / chiều dài / số lượng lớn nhất của các mặt hàng đã từng được yêu cầu cho đến nay. Vì vậy, điều sẽ xảy ra là vào đầu danh sách mảng sẽ tiếp tục tự phân bổ lại để tăng công suất khi bạn tiếp tục thêm các mục vào nó, nhưng đến một lúc nào đó, số lượng vật phẩm trung bình được thêm vào mỗi đơn vị thời gian chắc chắn sẽ khớp với số lượng vật phẩm trung bình bị loại bỏ trên mỗi đơn vị thời gian, (nếu không cuối cùng bạn sẽ hết bộ nhớ,) tại thời điểm đó, mảng sẽ ngừng phân bổ lại chính nó và tất cả các phụ lục sẽ được đáp ứng tại thời điểm không đổi của O (1).

Tuy nhiên, hãy nhớ rằng theo mặc định, loại bỏ ngẫu nhiên khỏi danh sách mảng không phải là O (1), đó là O (N), vì danh sách mảng di chuyển tất cả các mục sau khi vị trí bị xóa xuống một vị trí để thay thế vị trí bị xóa mục. Để đạt được O (1), bạn sẽ phải ghi đè hành vi mặc định để thay thế mục bị xóa bằng một bản sao của mục cuối cùng của danh sách mảng, sau đó xóa mục cuối cùng để không có mục nào bị di chuyển. Nhưng sau đó, nếu bạn làm điều đó, bạn không chính xác có một hàng đợi nữa.


1
Chết tiệt, điểm tốt về loại bỏ; Tôi đã không xem xét điều đó. Và vì chúng tôi loại bỏ các yếu tố một cách ngẫu nhiên, không có nghĩa là về mặt kỹ thuật, nó không còn là một hàng đợi theo nghĩa đó nữa?
Carcigenicate

Vâng, điều đó có nghĩa là bạn không thực sự coi nó như một hàng đợi. Nhưng tôi không biết làm thế nào bạn có kế hoạch để tìm các mục để loại bỏ. Nếu cơ chế tìm kiếm chúng của bạn hy vọng chúng có mặt trong hàng đợi theo thứ tự chúng được thêm vào, thì bạn đã hết may mắn. Nếu bạn không quan tâm nếu thứ tự của các mặt hàng bị cắt xén, thì bạn vẫn ổn.
Mike Nakis

2
Kỳ vọng là để tôi RandomQueuethực hiện Queuegiao diện và cho removephương thức được cung cấp để loại bỏ ngẫu nhiên thay vì bật đầu, vì vậy không nên có bất kỳ cách nào để dựa vào một thứ tự cụ thể. Tôi nghĩ với bản chất ngẫu nhiên của nó sau đó, người dùng không nên mong đợi nó sẽ giữ bất kỳ thứ tự cụ thể nào. Tôi trích dẫn bài tập trong câu hỏi của tôi để làm rõ. Cảm ơn bạn.
Carcigenicate

2
Vâng sau đó, có vẻ như bạn sẽ ổn nếu bạn chỉ cần đảm bảo rằng việc xóa mục được thực hiện theo cách tôi đề xuất.
Mike Nakis

Một điều cuối cùng nếu bạn không phiền. Tôi đã nghĩ về nó nhiều hơn và dường như không thể có cả bổ sung O (1) "đúng" và loại bỏ ngẫu nhiên "đúng" O (1); nó sẽ là một sự đánh đổi giữa 2. Bạn có cấu trúc được phân bổ đơn lẻ (như một mảng) cho phép loại bỏ nhưng không phải là additon hoặc cấu trúc phân bổ chunk như Danh sách liên kết cung cấp bổ sung nhưng không loại bỏ. Điều này có đúng không? Một lần nữa, cảm ơn bạn.
Carcigenicate

14

Câu hỏi dường như đặc biệt yêu cầu thời gian không đổi, và không phải là thời gian không đổi được khấu hao . Vì vậy, đối với câu hỏi được trích dẫn, không, chúng không thực sự giống nhau *. Có phải họ tuy nhiên trong các ứng dụng thế giới thực?

Vấn đề điển hình với hằng số khấu hao là đôi khi bạn phải trả khoản nợ tích lũy. Vì vậy, trong khi các phần chèn thường không đổi, đôi khi bạn phải chịu chi phí cho việc tái xác nhận mọi thứ một lần nữa khi một khối mới được phân bổ.

Trường hợp sự khác biệt giữa thời gian không đổi và thời gian không đổi được khấu hao có liên quan đến một ứng dụng phụ thuộc vào việc tốc độ rất chậm thường xuyên này có được chấp nhận hay không. Đối với một số lượng lớn các tên miền, điều này thường ổn. Đặc biệt nếu container có kích thước tối đa hiệu quả (như cache, bộ đệm tạm thời, container hoạt động), bạn có thể trả chi phí một cách hiệu quả chỉ một lần trong khi thực hiện.

Trong các ứng dụng quan trọng đáp ứng những thời điểm này có thể không được chấp nhận. Nếu bạn được yêu cầu đáp ứng một thời gian ngắn đảm bảo quay vòng, bạn không thể dựa vào một thuật toán đôi khi sẽ vượt quá điều đó. Tôi đã làm việc trên các dự án như vậy trước đây, nhưng chúng cực kỳ hiếm.

Nó cũng phụ thuộc vào chi phí thực sự cao như thế nào. Các vectơ có xu hướng hoạt động tốt vì chi phí phân bổ lại của chúng là tương đối thấp. Nếu bạn đi đến bản đồ băm, tuy nhiên việc phân bổ lại có thể cao hơn rất nhiều. Mặc dù một lần nữa, đối với hầu hết các ứng dụng có thể tốt, đặc biệt là các máy chủ tồn tại lâu hơn với giới hạn trên của các mục trong vùng chứa.

* Có một chút vấn đề ở đây. Để làm cho bất kỳ thùng chứa mục đích chung nào là thời gian không đổi để chèn một trong hai điều phải giữ:

  • Container phải có kích thước tối đa cố định; hoặc là
  • bạn có thể giả sử cấp phát bộ nhớ của các yếu tố riêng lẻ là thời gian không đổi.

"Máy chủ gan" dường như là một cụm từ kỳ lạ để sử dụng ở đây. Bạn có nghĩa là "máy chủ trực tiếp" có lẽ?
Pieter Geerkens

6

Nó phụ thuộc - vào việc bạn đang tối ưu hóa thông lượng hay độ trễ:

  • Hệ thống nhạy cảm độ trễ cần hiệu suất phù hợp. Đối với một kịch bản như vậy, chúng tôi phải nhấn mạnh hành vi trong trường hợp xấu nhất của hệ thống. Ví dụ là các hệ thống thời gian thực mềm như các trò chơi muốn đạt được tốc độ khung hình ổn định hoặc các máy chủ web phải gửi phản hồi trong một khung thời gian chặt chẽ nhất định: lãng phí chu kỳ CPU tốt hơn là trễ.
  • Các hệ thống được tối ưu hóa thông lượng không quan tâm đến các quầy hàng thường xuyên, miễn là lượng dữ liệu tối đa có thể được xử lý trong thời gian dài. Ở đây, chúng tôi chủ yếu quan tâm đến hiệu suất khấu hao. Đây thường là trường hợp cho crunching số hoặc công việc xử lý hàng loạt khác.

Lưu ý rằng một hệ thống có thể có các thành phần khác nhau phải được phân loại khác nhau. Ví dụ, một bộ xử lý văn bản hiện đại sẽ có một luồng UI nhạy cảm với độ trễ, nhưng các luồng được tối ưu hóa thông lượng cho các tác vụ khác như kiểm tra chính tả hoặc xuất PDF.

Ngoài ra, thuật toán phức tạp thường không quan trọng nhiều như chúng tôi muốn có thể nghĩ rằng: Khi một vấn đề được bao bọc với một số lượng nhất định, sau đó đặc tính hiệu suất thực tế và đo quan trọng hơn hành vi “cho rất lớn n ”.


Thật không may, tôi có rất ít nền tảng. Câu hỏi kết thúc bằng: "Các hoạt động add (x) và remove () trong RandomQueue sẽ chạy trong thời gian không đổi trên mỗi thao tác".
Carcigenicate

2
@Carcigenicate trừ khi bạn biết rằng hệ thống nhạy cảm với độ trễ, sử dụng độ phức tạp được khấu hao để chọn cấu trúc dữ liệu là hoàn toàn đủ.
amon

Tôi có ấn tượng đây có thể là một bài tập lập trình hoặc một bài kiểm tra. Và chắc chắn không phải là một điều dễ dàng. Hoàn toàn đúng rằng nó rất hiếm khi quan trọng.
gnasher729

1

Nếu bạn được yêu cầu thuật toán "khấu hao thời gian không đổi", thuật toán của bạn đôi khi có thể mất nhiều thời gian. Ví dụ: nếu bạn sử dụng std :: vector trong C ++, một vectơ như vậy có thể đã phân bổ không gian cho 10 đối tượng và khi bạn phân bổ đối tượng thứ 11, không gian cho 20 đối tượng được phân bổ, 10 đối tượng được sao chép và thêm 11 đối tượng mất thời gian đáng kể. Nhưng nếu bạn thêm một triệu đối tượng, bạn có thể có 999.980 hoạt động nhanh và 20 hoạt động chậm, với thời gian trung bình là nhanh.

Nếu bạn được yêu cầu thuật toán "thời gian không đổi", thuật toán của bạn phải luôn nhanh, cho mọi thao tác. Điều đó rất quan trọng đối với các hệ thống thời gian thực nơi bạn có thể cần một sự đảm bảo rằng mỗi hoạt động đơn lẻ luôn nhanh. "Thời gian không đổi" thường không cần thiết, nhưng nó chắc chắn không giống như "thời gian không đổi được khấu hao".

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.