Từ
- chúng đều là vùng chứa bộ nhớ liền kề nhau;
- tính năng khôn ngoan, deque có hầu hết mọi thứ mà vector có nhưng nhiều hơn thế, vì nó hiệu quả hơn khi chèn vào phía trước.
Tại sao whould ai thích std::vector
đến std::deque
?
Từ
Tại sao whould ai thích std::vector
đến std::deque
?
Câu trả lời:
Các yếu tố trong một deque
là không tiếp giáp trong bộ nhớ; vector
các yếu tố được đảm bảo. Vì vậy, nếu bạn cần tương tác với một thư viện C đơn giản cần các mảng liền nhau hoặc nếu bạn quan tâm (nhiều) về địa phương không gian, thì bạn có thể thích hơn vector
. Ngoài ra, vì có một số kế toán bổ sung, các hoạt động khác có thể đắt hơn (một chút) so với các vector
hoạt động tương đương của chúng . Mặt khác, việc sử dụng nhiều phiên bản / lớn vector
có thể dẫn đến phân mảnh heap không cần thiết (làm chậm các cuộc gọi đến new
).
Ngoài ra, như đã chỉ ra ở những nơi khác trên StackOverflow , có nhiều cuộc thảo luận hay hơn ở đây: http://www.gotw.ca/gotw/054.htm .
Để biết sự khác biệt, người ta nên biết cách deque
thực hiện chung. Bộ nhớ được cấp phát theo các khối có kích thước bằng nhau và chúng được xâu chuỗi với nhau (dưới dạng một mảng hoặc có thể là một vectơ).
Vì vậy, để tìm phần tử thứ n, bạn tìm khối thích hợp sau đó truy cập phần tử bên trong nó. Đây là thời gian không đổi, vì nó luôn luôn chính xác là 2 lần tra cứu, nhưng điều đó vẫn nhiều hơn véc tơ.
vector
cũng hoạt động tốt với các API muốn có bộ đệm liền kề vì chúng là API C hoặc linh hoạt hơn trong việc có thể lấy con trỏ và độ dài. (Vì vậy, bạn có thể có một vectơ bên dưới hoặc một mảng thông thường và gọi API từ khối bộ nhớ của bạn).
Nơi deque
có lợi thế lớn nhất của nó là:
Cái thứ hai trong số này ít được biết đến hơn, nhưng đối với kích thước bộ sưu tập rất lớn:
Trước đây, khi tôi xử lý các tập hợp lớn và chuyển từ mô hình liền kề sang mô hình khối, chúng tôi có thể lưu trữ một tập hợp lớn gấp khoảng 5 lần trước khi hết bộ nhớ trong hệ thống 32 bit. Điều này một phần là do, khi phân bổ lại, nó thực sự cần lưu trữ khối cũ cũng như khối mới trước khi sao chép các phần tử qua.
Đã nói tất cả những điều này, bạn có thể gặp rắc rối với std::deque
các hệ thống sử dụng phân bổ bộ nhớ "lạc quan". Trong khi nỗ lực của nó để yêu cầu kích thước bộ đệm lớn để phân bổ lại a vector
có thể sẽ bị từ chối vào một thời điểm nào đó với a bad_alloc
, bản chất lạc quan của bộ cấp phát có khả năng luôn cấp yêu cầu cho bộ đệm nhỏ hơn do a yêu cầu deque
và điều đó có thể gây ra hệ điều hành giết một tiến trình để cố gắng lấy một số bộ nhớ. Bất kỳ cái nào nó chọn có thể không quá dễ chịu.
Các giải pháp thay thế trong trường hợp này là đặt cờ cấp hệ thống để ghi đè phân bổ lạc quan (không phải lúc nào cũng khả thi) hoặc quản lý bộ nhớ theo cách thủ công hơn, ví dụ: sử dụng trình cấp phát của riêng bạn để kiểm tra việc sử dụng bộ nhớ hoặc tương tự. Rõ ràng là không lý tưởng. (Có thể trả lời câu hỏi của bạn là thích vectơ hơn ...)
Tôi đã triển khai cả vector và deque nhiều lần. deque cực kỳ phức tạp hơn từ quan điểm triển khai. Sự phức tạp này chuyển thành nhiều mã hơn và mã phức tạp hơn. Vì vậy, bạn thường thấy kích thước mã được nhấn khi bạn chọn deque trên vector. Bạn cũng có thể gặp phải một tốc độ nhỏ nếu mã của bạn chỉ sử dụng những thứ mà vectơ vượt trội (tức là push_back).
Nếu bạn cần một hàng đợi kết thúc kép, deque là người chiến thắng rõ ràng. Nhưng nếu bạn đang thực hiện hầu hết các lần chèn và xóa ở phía sau, thì vector sẽ là người chiến thắng rõ ràng. Khi bạn không chắc chắn, hãy khai báo vùng chứa của bạn với một typedef (vì vậy dễ dàng chuyển đổi qua lại) và đo lường.
vector
.) Tôi đã viết một triển khai được liên kết với bên dưới trong câu trả lời của tôi . Nó có thể nhanh như một vector
nhưng áp dụng rộng rãi hơn nhiều (ví dụ: khi thực hiện một hàng đợi nhanh).
std::deque
không có bộ nhớ liên tục được đảm bảo - và nó thường hơi chậm hơn đối với truy cập được lập chỉ mục. Một deque thường được triển khai dưới dạng "danh sách các vectơ".
Theo http://www.cplusplus.com/reference/stl/deque/ , "không giống như vectơ, deques không được đảm bảo có tất cả các phần tử của nó ở các vị trí lưu trữ liền kề, do đó loại bỏ khả năng truy cập an toàn thông qua số học con trỏ."
Deques phức tạp hơn một chút, một phần vì chúng không nhất thiết phải có bố cục bộ nhớ liền nhau. Nếu bạn cần tính năng đó, bạn không nên sử dụng deque.
(Trước đây, câu trả lời của tôi đưa ra sự thiếu chuẩn hóa (từ cùng một nguồn như trên, "deques có thể được triển khai bởi các thư viện cụ thể theo những cách khác nhau"), nhưng điều đó thực sự áp dụng cho bất kỳ kiểu dữ liệu thư viện chuẩn nào.)
std::deque
được tiêu chuẩn hóa không kém hơn std::vector
. Tôi không tin rằng std::deque
có thể đáp ứng các yêu cầu phức tạp đối với bộ nhớ liền kề.
deque
không thể đáp ứng với bộ nhớ liền kề?
deque
, cụ thể là phần chèn ở các đầu sẽ không làm mất hiệu lực được tham chiếu đến các phần tử hiện có. Yêu cầu này ngụ ý bộ nhớ không liên tục.
Tôi nghĩ rằng ý tưởng hay để thực hiện kiểm tra hiệu suất của từng trường hợp. Và đưa ra quyết định dựa trên các bài kiểm tra này.
Tôi muốn std::deque
hơn std::vector
trong hầu hết các trường hợp.
vector
. Chúng ta có thể suy ra rằng tại sao không phải là một hệ quả tất yếu. Nói rằng bạn thích deque
, vì những lý do không xác định, từ các bài kiểm tra không xác định, không phải là một câu trả lời.
Bạn sẽ không thích vectơ để deque theo các kết quả thử nghiệm này (có nguồn).
Tất nhiên, bạn nên thử nghiệm trong ứng dụng / môi trường của mình, nhưng tóm lại:
Mặt khác, vector thường nhanh hơn deque. Nếu bạn không thực sự cần tất cả các tính năng của deque, hãy sử dụng một vector.
Mặt khác, đôi khi bạn làm các tính năng cần thiết mà vector không cung cấp cho bạn, trong trường hợp này bạn phải sử dụng một deque. Ví dụ: tôi thách thức bất kỳ ai cố gắng viết lại mã này , mà không sử dụng deque và không thay đổi nhiều thuật toán.
push_back
và pop_back
hoạt động, deque<int>
luôn nhanh hơn ít nhất 20% so với vector<int>
trong các thử nghiệm của tôi (gcc với O3). Tôi đoán đó là lý do tại sao deque
là lựa chọn tiêu chuẩn cho những thứ như std::stack
...
Lưu ý rằng bộ nhớ vectơ được cấp phát lại khi mảng phát triển. Nếu bạn có con trỏ đến các phần tử vectơ, chúng sẽ trở nên không hợp lệ.
Ngoài ra, nếu bạn xóa một phần tử, các trình vòng lặp sẽ trở nên không hợp lệ (nhưng không phải là "for (auto ...)").
Chỉnh sửa: đã thay đổi 'deque' thành 'vector'
std::deque
có kích thước khối tối đa rất nhỏ (~ 16 byte, nếu tôi nhớ chính xác; có thể là 32), và như vậy không hoạt động rất tốt cho các ứng dụng thực tế. Adeque<T>
trong đósizeof(T) > 8
(hoặc 16? Đó là một số nhỏ) có các đặc tính hiệu suất tương tự như avector<T*>
, trong đó mỗi phần tử được phân bổ động. Các triển khai khác có kích thước khối tối đa khác nhau, do đó khó viết mã có các đặc tính hiệu suất tương đối giống nhau trên các nền tảng khác nhaudeque
.