Từ điển vs Danh sách


30

Vì vậy, tôi chạy vào một Dictionary<int, int>ngày hôm nay tại nơi làm việc. Điều này có vẻ kỳ lạ đối với tôi bởi vì tôi có lẽ chỉ cần sử dụng một List<int>thay thế. Có một sự khác biệt và sẽ có một trường hợp sử dụng trong đó một cấu trúc sẽ được ưu tiên hơn cấu trúc kia?


1
Có cần phải có một mối quan hệ giữa hai (hoặc nhiều) ints nhất định không? Sau đó, bản đồ (từ điển trong ngôn ngữ này) có ý nghĩa.
Rig

3
Từ điển tên làm cho nó rõ ràng với tôi. Khi bạn cần tìm kiếm một cái gì đó nhanh chóng, bạn sử dụng một từ điển.
ChaosPandion

2
@ChaosPandion: a List<T>trong .NET framework là một mảng truy cập ngẫu nhiên, trong đó thao tác tra cứu thường nhanh hơn so với a Dictionary<int,T>.
Doc Brown

2
@DocBrown - Chỉ trong trường hợp khá kỳ lạ khi sử dụng chỉ mục số làm khóa. Thông thái khác, việc tìm kiếm sẽ nhanh hơn khi sử dụng Dictionary<TKey, TValue>.
ChaosPandion

2
@chaos câu hỏi này là về trường hợp kỳ lạ đó.
MarkJ

Câu trả lời:


32

Bạn sẽ sử dụng Dictionary<int, int>nếu chỉ mục của bạn có ý nghĩa đặc biệt bên cạnh vị trí vị trí.

Ví dụ ngay lập tức xuất hiện trong tâm trí là lưu trữ một cột id và một cột int trong cơ sở dữ liệu. Ví dụ: nếu bạn có một [person-id]cột và một [personal-pin]cột, thì bạn có thể đưa chúng vào một Dictionary<int, int>. Cách này pinDict[person-id]cung cấp cho bạn mã PIN, nhưng chỉ mục có ý nghĩa và không chỉ là một vị trí trong a List<int>.

Nhưng thực sự, bất cứ khi nào bạn có hai danh sách số nguyên liên quan, đây có thể là một cấu trúc dữ liệu phù hợp.


Nếu id cá nhân của tôi nằm trong phạm vi 0, ..., 999 và tôi sẽ phải tải các giá trị pin cá nhân vào bộ nhớ cho tất cả 1000 người, tôi thường sẽ chọn một List<int>, chứ không phải từ điển. Xem câu trả lời của tôi dưới đây.
Doc Brown

3
có nhưng một từ điển có thể thưa thớt
jk.

@jk: đó chính xác là những gì tôi đã cố gắng xây dựng trong câu trả lời của mình.
Doc Brown

7
Mã Pin cá nhân? Âm thanh hơi dư thừa.
Jack

Hừm, khi chỉ mục có "ý nghĩa đặc biệt", trong các tình huống trong thế giới thực, có thể chúng không tạo thành một phạm vi liền kề [0, ..., n] (mặc dù điều này không bắt buộc), vì vậy câu trả lời này là không sai, nhưng không chính xác. Tuy nhiên, IMHO quyết định không nên dựa trên "điều có ý nghĩa đặc biệt" này mà chỉ dựa trên "các khóa xây dựng khoảng một khoảng [0, ..., n]". Dựa trên số lượng upvote tôi đoán hầu hết độc giả đã bỏ lỡ điểm đó.
Doc Brown

28

Hãy nghĩ về Listmột mảng và Dictionarynhư một bảng băm . Bạn sẽ chỉ sử dụng Dictionarynếu bạn cần ánh xạ (hoặc liên kết) các khóa có ý nghĩa với các giá trị, trong khi đó Listchỉ ánh xạ (hoặc liên kết) vị trí (hoặc chỉ mục) thành các giá trị.

Ví dụ: giả sử bạn muốn lưu trữ mối liên hệ giữa tuổi của một người và chiều cao của họ. Bạn có thể sử dụng a Dictionary<int, int>để ánh xạ tuổi của người đó (an int) theo chiều cao của họ (an int):

Dictionary<int, int> personHeightMap = new Dictionary<int, int>();

personHeightMap.Add(21, 185);
personHeightMap.Add(31, 174);

int height = personHeightMap.ContainsKey(21) ? personHeightMap[21] : -1;

Không phải là một ví dụ rất hữu ích, nhưng vấn đề là bạn sẽ không thể làm điều này một cách tao nhã với một Listvì nó sẽ cần lưu trữ các giá trị này một cách định vị.


7
+1 để đề cập rằng một Listgiao dịch với đơn đặt hàng , trong đó một Dictionarygiao dịch với hiệp hội . Nếu bạn cần nhận được dữ liệu của mình theo một thứ tự nhất định mỗi lần hoặc thứ tự của chúng liên quan đến nhau là quan trọng, thì đó Listlà cách để đi. Dictionariescó xu hướng không được sắp xếp và xử lý khóa ánh xạ -> các mối quan hệ giá trị.
KChaloux

2
Cuối cùng, khi bạn biết những gì bạn đang tìm kiếm, bảng băm có khoảng thời gian O (1), trong khi mảng là O (logN) trong trường hợp tốt nhất (được sắp xếp và w / o trùng lặp) và O (N) trong trường hợp xấu nhất.
JensG

1
+1. Không ai khác dường như đã giải quyết vấn đề rằng các danh sách được sắp xếp theo ngữ nghĩa và theo tôi là tìm kiếm về mặt ngữ nghĩa, điều này hoàn toàn cơ bản , theo ý kiến ​​của tôi.
Benjamin Hodgson

15

Về mặt ngữ nghĩa, a Dictionary<int, T>List<T>rất giống nhau, cả hai đều là các thùng chứa truy cập ngẫu nhiên của khung .NET. Để sử dụng danh sách thay thế cho từ điển, bạn cần một giá trị đặc biệt trong loại T(như null) để thể hiện các vị trí trống trong danh sách của bạn. Nếu Tkhông phải là loại intkhông có int?giá trị như , bạn có thể sử dụng thay thế hoặc nếu bạn chỉ muốn lưu trữ giá trị dương, bạn cũng có thể sử dụng giá trị đặc biệt như -1 để thể hiện các vị trí trống.

Cái nào bạn sẽ chọn nên phụ thuộc vào phạm vi của các giá trị chính. Nếu các khóa của bạn Dictionary<int, T>nằm trong một khoảng nguyên, không có nhiều khoảng trống giữa chúng (ví dụ: 80 giá trị trong số [0, ... 100]), thì a List<T>sẽ phù hợp hơn, vì việc truy cập theo chỉ mục nhanh hơn và có ít bộ nhớ và thời gian hơn so với từ điển trong trường hợp này.

Nếu các giá trị khóa của bạn là 100 intgiá trị từ một phạm vi như [0, ..., 1000000], thì List<T>bộ nhớ cần có 1000000 giá trị T, trong đó từ điển của bạn sẽ chỉ cần bộ nhớ theo thứ tự cường độ khoảng 100 giá trị T, 100 giá trị của int (cộng với một số chi phí, trong thực tế, cần khoảng 2 lần bộ nhớ để lưu trữ 100 khóa và giá trị đó). Vì vậy, trong trường hợp sau, một từ điển sẽ phù hợp hơn.


6
Đây là sự khác biệt quan trọng imho, Từ điển <int, int> có thể thưa thớt
jk.

Trong trường hợp đó, chúng tôi không thể sử dụng Danh sách <KeyValuePair <int, int >>? Cái nào sẽ tốt hơn cho truyền tải tuyến tính?
Deepak Mishra

@DeepakMishra: sự khác biệt chính ở đây là, List<KeyValuePair<int,T>>không có thao tác tra cứu O (1) nào khả dụng. Thứ hai, các yếu tố trong List<KeyValuePair<int,T>>có thể có một thứ tự cụ thể, độc lập với các giá trị chính của chúng. Nếu bạn cần cái sau nhưng không phải cái trước, List<KeyValuePair<int,T>>hoặc List<Tuple<int,T>>có thể là lựa chọn tốt hơn. Nếu bạn cần cả hai, cũng có OrderedDictionary.
Doc Brown

@DocBrown Cái nào sẽ tốt hơn cho truyền tải tuyến tính (tức là foreach) và thao tác chèn, không cần tra cứu trực tiếp?
Deepak Mishra

@DeepakMishra: không có thứ gọi là "nói chung là tốt hơn" trong phát triển phần mềm. Tốt hơn ở đây có thể có nghĩa là nhanh hơn, tốt hơn để đọc, ít mã hơn để gõ, dễ dàng mở rộng hơn cho các yêu cầu sắp tới. Nhưng nói chung, hãy dừng việc xem xét lại vấn đề này, thực hiện một cách giải quyết vấn đề của bạn một cách chính xác và đơn giản nhất trong mắt bạn , kiểm tra xem nó có đủ nhanh cho mục đích của bạn không và chỉ đầu tư nhiều suy nghĩ vào nó khi bạn quan sát những nhược điểm.
Doc Brown

6

Làm thế nào bất cứ ai có thể coi chúng tương đương?

Từ điển thưa thớt và cho phép chèn ngẫu nhiên nhưng làm cho việc truyền tải theo thứ tự trở thành một vấn đề, Danh sách không thưa thớt và việc chèn theo thứ tự rất tốn kém, vốn dĩ nó cung cấp dịch vụ theo thứ tự.

Sẽ có rất ít tình huống mà một người không vượt trội so với người kia.


2

Ngoài ra: Các ngôn ngữ lập trình khác đề cập đến loại cấu trúc dữ liệu này dưới dạng Bản đồ, thay vì Từ điển.

Nếu dữ liệu của bạn có thể được định nghĩa một cách có ý nghĩa là các cặp khóa / giá trị, thì Từ điển sẽ cung cấp quyền truy cập nhanh hơn nhiều nếu bạn cần tìm một giá trị bằng khóa của nó.

Ví dụ: giả sử bạn có một danh sách Khách hàng. Mỗi Khách hàng bao gồm các chi tiết như tên và địa chỉ và một số khách hàng duy nhất. Giả sử bạn cũng có một danh sách các Đơn đặt hàng đang được xử lý. Mỗi Đơn hàng sẽ chứa thông tin chi tiết về những gì đang được thực hiện và sẽ cần bao gồm số khách hàng của người đã đặt hàng.

Khi một đơn đặt hàng đã sẵn sàng để vận chuyển, bạn cần tìm địa chỉ để gửi nó đến. Nếu khách hàng được lưu trữ dưới dạng Danh sách đơn giản, thì bạn cần tìm kiếm toàn bộ danh sách để tìm khách hàng với đúng số khách hàng. Thay vào đó, bạn có thể lưu trữ khách hàng trong Từ điển, với số khách hàng là chìa khóa. Từ điển bây giờ sẽ cho phép bạn kéo đúng khách hàng trong một bước mà không cần tìm kiếm.


1

Từ điển sử dụng băm để tìm kiếm dữ liệu. Từ điển trước tiên tính giá trị băm cho khóa và giá trị băm này dẫn đến nhóm dữ liệu đích. Sau đó, mỗi phần tử trong thùng cần được kiểm tra sự bằng nhau. Nhưng thực sự danh sách sẽ nhanh hơn từ điển trong tìm kiếm mục đầu tiên vì không có gì để tìm kiếm trong bước đầu tiên. Nhưng trong bước thứ hai, danh sách phải xem qua mục đầu tiên, và sau đó là mục thứ hai. Vì vậy, mỗi bước tìm kiếm mất nhiều thời gian hơn. Danh sách càng lớn thì càng mất nhiều thời gian.

Thêm về .... Từ điển Vs List với ví dụ.


-1

Nếu mã trong câu hỏi đang lưu trữ hai bộ giá trị tương quan, lớp Từ điển cung cấp một cách lập chỉ mục để tìm kiếm các giá trị bằng một khóa. Nếu chỉ có một bộ giá trị, nhưng bộ đó cần được truy cập ngẫu nhiên (có lẽ để kiểm tra sự tồn tại của khóa trong một bộ) các giá trị là duy nhất, Hashset có thể là lớp được đặt tốt nhất để sử dụng.


-3

Đây là những câu trả lời tuyệt vời mà dường như bao gồm các căn cứ.

Một cân nhắc khác tôi sẽ đưa ra là Từ điển (trong C #) phức tạp hơn từ góc độ mã hóa. Việc có cả danh sách và từ điển trong cùng một cơ sở mã khiến cho mã của bạn khó duy trì hơn vì cả hai phương pháp đều có sự khác biệt tinh tế trong cách thực hiện các hoạt động cơ bản như tìm kiếm và sắp xếp dữ liệu đối tượng. Quan điểm của tôi là trừ khi bạn cần một từ điển cho một số lý do chính đáng, hãy sử dụng một danh sách.


8
Tôi không đồng ý. Từ điển / bản đồ là một cấu trúc dữ liệu cơ bản mà mọi kỹ sư phần mềm nên làm quen với nó. Dù bằng cách nào: bạn sẽ cần một lý do chính đáng để sử dụng bất kỳ cấu trúc dữ liệu nào; bao gồm cả Danh sách.
Steven Evers
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.