Khi nào nên sử dụng vector / danh sách?


17

Tôi có thể hiểu khi nào nên sử dụng danh sách, nhưng tôi không hiểu khi nào nên sử dụng vectơ tốt hơn là sử dụng danh sách trong trò chơi video: khi nào nên truy cập ngẫu nhiên nhanh hơn?

(Và tôi hiểu tại sao việc chèn / xóa nhanh hơn trong danh sách vì nó chỉ xóa / thêm con trỏ, nhưng nó vẫn phải tìm mục tương ứng ...)


Đã thêm lại thẻ vectơ vào đây - nếu danh sách là thẻ hợp lệ, thì vectơ cũng vậy.
Kylotan

Có lẽ vectơ đã bị xóa vì nó được dùng để chỉ vectơ toán học, không phải std :: vector.

1
Làm thế nào về nix cả hai và đặt container.
deft_code

@Kylotan: Đúng như Joe nói. Câu hỏi này chắc chắn là về vectơ, nhưng nó không thuộc về thẻ vectơ.
doppelgreener

1
Vì vậy, chúng tôi loại bỏ bất kỳ thẻ mơ hồ? Nghe có vẻ như quyết định sai đối với tôi - tốt hơn là tìm kiếm của bạn xuất hiện quá nhiều thông tin hơn là không đủ. Bỏ qua kết quả không mong muốn dễ dàng hơn là động não để tìm từ đồng nghĩa.
Kylotan

Câu trả lời:


29

Nguyên tắc nhỏ của tôi, và tôi chắc chắn sẽ có tranh luận về vấn đề này, là không bao giờ sử dụng danh sách (trừ khi bạn cần loại bỏ rất, rất thường xuyên những thứ ở giữa danh sách lớn).

Tốc độ bạn sẽ đạt được bằng cách để tất cả các thành phần của bạn trong bộ nhớ của bạn trong bộ nhớ liền kề (và do đó thân thiện với bộ đệm hơn) đáng để bù đắp cho các chi phí bổ sung khi thêm / xóa / thay đổi kích thước vectơ.

Chỉnh sửa: Chỉ cần làm rõ hơn một chút, tất nhiên là không cần phải nói rằng bất kỳ loại câu hỏi "nào nhanh hơn" nên được kiểm tra trên bất kỳ nền tảng nào với bất kỳ bộ dữ liệu nào phù hợp với nhu cầu cụ thể của bạn. Nếu tôi chỉ cần một tập hợp các phần tử, tôi chỉ sử dụng vectơ (hoặc deque, gần như giống nhau) trừ khi có lý do chính đáng để không .


1
Tôi nghĩ nó phụ thuộc nhiều vào nhu cầu của bạn, nếu bạn không bao giờ cần truy cập vào một yếu tố cụ thể và chỉ cần đọc tất cả chúng và bạn thêm và xóa các yếu tố thường xuyên, danh sách là một giải pháp tốt hơn.
Frédérick Imbeault

11
@ Frédérick: Đó là sự khôn ngoan tiêu chuẩn của C ++, nhưng nó cũng hầu như luôn luôn sai. Các vectơ, đặc biệt là khi xử lý các vectơ con trỏ (mà bạn hầu như luôn dành cho các trò chơi), cực kỳ nhanh chóng để loại bỏ nội dung từ giữa - đó là thời gian tuyến tính, nhưng đó là chi phí rất nhỏ cho mỗi mục. Nó cũng nhanh hơn nhiều để lặp lại tuần tự trên một vectơ.

1
Tôi không chắc chắn loại cấu trúc nào bạn nhận được chính xác - loại tối ưu hóa này đòi hỏi các ví dụ cụ thể để nói bất cứ điều gì dứt khoát. Ví dụ, phản ứng đầu tiên của tôi đối với trường hợp sử dụng của bạn sẽ là một tập hợp không có thứ tự, cho phép chèn, xóa và tra cứu nhanh như nhau; trong bộ kinh nghiệm của tôi là tuyệt vời cho các đối tượng trong trình soạn thảo. Nhưng vì các biên tập viên có nhiều yêu cầu về hiệu suất thời gian thực lỏng lẻo hơn - ví dụ như việc trả lời nút "Xóa" sẽ mất 1/20 giây hoặc mất 1/2 giây trong 10% thời gian - mức tối ưu hóa này cũng hiếm khi áp dụng cho họ.

1
@ Frédérick Imbeault Đã sửa đổi không phải là vấn đề, đó là Thêm \ Xóa gây ra sự cố. Từ add \ remove point đến cuối vectơ được sao chép để giữ cho vectơ tiếp giáp nhau. Nếu thứ tự phần tử không thành vấn đề, bạn có thể trao đổi phần tử đã xóa với phần tử cuối cùng, sau đó bật phần tử đó để xóa và thêm vào phần cuối để thêm.
ném đá

4
Chắc chắn, lấy địa chỉ của một phần tử trong một vectơ và lưu trữ nó không an toàn. Nhưng nói chung, bạn hầu như không bao giờ làm điều đó, thay vào đó thích có một vectơ con trỏ của các phần tử và sao chép con trỏ xung quanh (hoặc một cái gì đó tương tự).
Tết

8

Sử dụng danh sách khi việc vô hiệu hóa trình lặp gây ra bằng cách sửa đổi giữa cấu trúc dữ liệu của bạn sẽ gây ra sự cố hoặc bạn cần giữ các phần tử của mình được sắp xếp để trao đổi và lừa pop để xóa bộ sưu tập giữa nhanh sẽ không hoạt động và bạn có số lượng lớn số lần xóa bộ sưu tập giữa.

Bạn cũng có thể muốn xem xét sử dụng Deque. Nó có các đặc tính hiệu suất tương tự như một vectơ nhưng không có nhu cầu về bộ nhớ liền kề của vectơ và linh hoạt hơn một chút.


+1 vì là người duy nhất đề cập đến các deques - bạn có được bộ nhớ liền kề và lợi ích tốc độ tra cứu của vectơ, với việc chèn / xóa nhanh ở cả hai đầu.

5

Sự lựa chọn của bạn nên phản ánh nhu cầu của bạn. Tất cả các phần tử của vectơ là liên tục trong bộ nhớ và các danh sách có con trỏ tới các phần tử tiếp theo / trước để mỗi phần tử có lợi thế / biến dạng của chúng:

Danh sách:

  • Mỗi phần tử cần 2 số nguyên để trỏ các phần tử trước và phần tử tiếp theo, vì vậy, thông thường nhất, đó là thêm 8 byte cho mỗi phần tử trong danh sách của bạn
  • Chèn là tuyến tính trong thời gian: O (n)
  • Xóa là một hoạt động liên tục: O (1)
  • Truy cập phần tử x là tuyến tính theo thời gian: O (n)

Vectơ:

  • Cần ít bộ nhớ hơn (không có con trỏ đến các yếu tố khác, đó là một thuật toán toán học đơn giản)
  • Xóa là tuyến tính trong thời gian: O (n)
  • Truy cập phần tử x là hằng số: O (1) (Đó là do các phần tử được liên tục trong bộ nhớ nên đó là một phép toán đơn giản vectorPtr + (x * byteOfTheType))
  • Chèn có thể theo thời gian tuyến tính, nhưng thông thường nhất, đó là hoạt động không đổi: O (1) (Đó là vì vectơ trong một mảng nhưng luôn dự trữ gấp 2 lần dung lượng của nó khi mảng đầy nên sao chép mảng không thường xuyên)

Vì vậy, danh sách sẽ tốt hơn khi chương trình của bạn cần thêm và xóa các phần tử thường xuyên, nhưng không bao giờ truy cập (hoặc hiếm khi truy cập) một phần tử cụ thể mà không cần các phần tử khác trước đó. Các vectơ nên được sử dụng cho thời gian truy cập tốt hơn, nhưng thiếu hiệu quả khi bạn cần loại bỏ hoặc thêm các yếu tố.

Kiểm tra bài đăng này trên stackoverflow, nó trình bày một biểu đồ thực sự hay với các câu hỏi cơ bản về nhu cầu của bạn đưa bạn đến một thùng chứa cụ thể tùy thuộc vào câu trả lời của bạn:

/programming/366432/extending-stdlist


3
Biểu đồ đó thực sự cần bắt đầu với nút "Bạn đang lưu trữ con trỏ và ít hơn một nghìn? Không -> vectơ".

Có lẽ bạn đúng, tôi đã không xem xét loại được lưu trữ nó cũng nên được phân tích.
Frédérick Imbeault

2

Thông thường các danh sách được sử dụng cho các cấu trúc như hàng đợi nơi có nhiều hoạt động chắp thêm và xóa. Ví dụ: Một danh sách các thực thể cần thay đổi cần được cập nhật. Bản thân danh sách chỉ chứa các thực thể trên màn hình và do đó thay đổi thường xuyên.

Các vectơ (hoặc mảng) phù hợp hơn cho một bộ sưu tập không thay đổi nhiều và nơi bạn cần truy cập nhanh vào các mục riêng lẻ trong bộ sưu tập. Ví dụ: Bản đồ ô trong đó bạn phải tra cứu các ô tại một chỉ mục nhất định.

Ý kiến ​​của Tetrad có thể đúng, nhưng nó phụ thuộc vào ngôn ngữ lập trình được sử dụng. Tôi thấy rằng bạn đã gắn thẻ câu hỏi của bạn c++, nhưng tôi đã cố gắng đưa ra một câu trả lời không dành riêng cho ngôn ngữ.


Chà, tôi cũng có thể đã đặt C vào đó, nhưng không có các thùng chứa như vậy trong C, nhưng đó là điều cần suy nghĩ: có một số thư viện giống như STL cho C không?
jokoon

Trước đây tôi đã sử dụng glib ( library.gnome.org/devel/glib ), trong đó thực hiện một số cấu trúc dữ liệu tiêu chuẩn cho C. Tôi ghét nó vì nó thường quá dài dòng và rất muốn trở thành C ++, nhưng nó đã trưởng thành và ổn định.

0

Trong các game console, chúng tôi không bao giờ sử dụng std :: list vì:

  1. nó phân bổ bộ nhớ bất cứ khi nào bạn thêm một mục mới. cấp phát bộ nhớ chậm.
  2. nó đầy con trỏ con trỏ là xấu. một con trỏ là một bộ nhớ cache. một lỗi nhớ cache là xấu.

thậm chí std :: vector đang mất dần sự ưu ái trên bảng điều khiển vì:

  1. bạn thường chỉ quan tâm, ví dụ, vị trí của tất cả các đối tượng. ví dụ như bạn muốn va chạm các vật thể với nhau, trong trường hợp đó bạn không quan tâm màu sắc của chúng là gì. Vì vậy, bạn muốn tất cả các vị trí tiếp giáp nhau trong bộ nhớ và bạn muốn màu sắc ở một nơi khác rất xa, để tránh làm ô nhiễm bộ đệm. nhưng std :: vector yêu cầu bạn lưu trữ mọi thứ cho từng đối tượng trong một đoạn bộ nhớ liền kề (ví dụ như vị trí rồi màu sắc.) vì vậy nếu bạn làm việc chỉ đọc các vị trí, bạn cũng cần đọc tất cả các màu vào bộ đệm. nếu bạn không sử dụng chúng. Điều này là lãng phí.

5
@bmcnett "[] .. nhưng std :: vector yêu cầu bạn lưu trữ mọi thứ cho từng đối tượng trong một đoạn bộ nhớ liền kề" - đó không phải là câu hỏi của container, đó là câu hỏi về bố cục dữ liệu của bạn, bạn có thể có tất cả vị trí trong một đoạn bộ nhớ liên tục với một std :: vector:struct point{float x, y, z, w}; std::vector<point> positions;
Maik Semder

trường tôi sẽ thích điều này :)
jokoon

2
-1 bởi vì câu trả lời này không thêm bất cứ điều gì vào danh sách so với thảo luận về vectơ đã có ở đây và tuyên bố của nó về vector gây ô nhiễm bộ đệm là sai, như Maik nói.

bạn đã hiểu nhầm yêu cầu của tôi. tôi không bao giờ nói rằng trong số tất cả các container std :: vector đặc biệt có tội gây ô nhiễm bộ đệm. tất cả các container, và trên thực tế ngay cả các mảng, đều có tội như nhau về điều đó. std :: vector đang giảm giá vì các đối tượng C ++ không được ưa chuộng. C ++ yêu cầu rằng dữ liệu của mỗi đối tượng phải liền kề nhau trong bộ nhớ. bạn có thể khắc phục điều đó bằng cách tránh các đối tượng C ++, ví dụ bằng cách sử dụng std :: vector <vị trí> như đã đề cập ở trên.
bmcnett

3
Ngoại trừ pointlà một đối tượng C ++ (như là std::vector, một cái gì đó đơn giản như float). Tôi biết sự khác biệt mà bạn đang cố gắng vẽ, nhưng bạn đang làm một công việc tồi tệ để giải thích nó.
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.