Bộ sưu tập .NET nào cung cấp tìm kiếm nhanh nhất


143

Tôi có 60k mặt hàng cần được kiểm tra đối với danh sách tra cứu 20k. Có một đối tượng bộ sưu tập (như List, HashTable) cung cấp một Contains()phương thức cực kỳ nhanh không? Hay tôi sẽ phải tự viết? Nói cách khác, là Contains()phương pháp mặc định chỉ quét từng mục hoặc sử dụng thuật toán tìm kiếm tốt hơn.

foreach (Record item in LargeCollection)
{
    if (LookupCollection.Contains(item.Key))
    {
       // Do something
    }
}

Lưu ý . Danh sách tra cứu đã được sắp xếp.


Chứa danh sách không hoạt động cho danh sách các đối tượng vì nó so sánh các tham chiếu.
Fiur

2
Sắp xếp dữ liệu? Tìm kiếm nhị phân - xem câu trả lời của @ Mark.
Hamish Smith

HashtTable đánh bại mọi thứ lên tới 2 triệu vật phẩm theo kinh nghiệm của tôi
Chris S

Bên cạnh đó, nếu các yếu tố của bạn theo thứ tự có ý nghĩa và được phân phối khá đều, bạn có thể thực hiện tìm kiếm nhị phân nhanh hơn nhiều bằng cách đoán lần đầu tiên trong phạm vi ước tính của mặt hàng của bạn. Điều này có thể có hoặc không có bất kỳ ý nghĩa cho ứng dụng cụ thể của bạn.
Brian

2
Đừng quên System.Collections.Generic.SortList (TKey, TValue) nếu bạn muốn đơn giản hóa công cụ này nhưng tránh băm.
Brian

Câu trả lời:


141

Trong trường hợp chung nhất, hãy xem xét System.Collections.Generic.HashSetcấu trúc dữ liệu công việc "Chứa" mặc định của bạn, bởi vì phải mất thời gian liên tục để đánh giá Contains.

Câu trả lời thực tế cho "Bộ sưu tập có thể tìm kiếm nhanh nhất là gì" tùy thuộc vào kích thước dữ liệu cụ thể, mức độ đặt hàng, chi phí băm và tần suất tìm kiếm.


36
Lưu ý: Đừng quên ghi đè chức năng băm. Để thêm hiệu suất, hãy tạo trước mã băm của bạn trong hàm tạo của bạn.
Brian

1
@Brian: điểm tốt. Tôi đã giả sử (vô căn cứ) Record.Key là một loại dựng sẵn của một số loại.
Jimmy

3
@Brian: thay vì tiền phát hành, tôi thích lưu trữ cái đã tạo lần đầu tiên, tại sao để làm chậm công cụ xây dựng với thứ gì đó bạn không biết nếu nó sẽ được sử dụng?
jmservera

8
FYI: Kiểm tra hiệu suất - Tôi đã tạo một so sánh giữa Danh sách <T> và Hashset <T> cho chuỗi. Tôi thấy rằng Hashset nhanh hơn khoảng 1000 lần so với Danh sách.
Quango

10
@Quango: 3 năm sau, nhưng thực sự nếu bạn không chỉ định kích thước của dữ liệu của mình thì so sánh hiệu suất này có nghĩa là không có gì: Hashsets có tìm kiếm O (1), danh sách có tìm kiếm O (n), vì vậy tỷ lệ hiệu suất tỷ lệ thuận với n.
Clément


24

Bạn đã xem xét List.BinarySearch(item)chưa?

Bạn nói rằng bộ sưu tập lớn của bạn đã được sắp xếp để đây có vẻ là cơ hội hoàn hảo? Băm chắc chắn sẽ là nhanh nhất, nhưng điều này mang lại những vấn đề của riêng nó và đòi hỏi nhiều chi phí hơn cho việc lưu trữ.


1
Bạn đã đúng, một hàm băm có thể mang lại một số vấn đề không mong muốn khi sử dụng các đối tượng có thể thay đổi làm khóa.
jmservera

10

Bạn nên đọc blog này rằng tốc độ đã thử nghiệm một số loại bộ sưu tập và phương pháp khác nhau cho từng loại bằng cách sử dụng cả kỹ thuật đơn và đa luồng.

Theo kết quả, BinarySearch trong Danh sách và Sắp xếp danh sách là những người biểu diễn hàng đầu liên tục chạy cổ khi tìm kiếm thứ gì đó như một "giá trị".

Khi sử dụng một bộ sưu tập cho phép "khóa", Từ điển, Đồng thời Từ điển, Hashset và HashTables thực hiện tổng thể tốt nhất.


4

Giữ cả hai danh sách x và y theo thứ tự sắp xếp.

Nếu x = y, hãy thực hiện hành động của bạn, nếu x <y, tiến x, nếu y <x, tiến y cho đến khi một trong hai danh sách trống.

Thời gian chạy của giao lộ này tỷ lệ với min (kích thước (x), kích thước (y))

Đừng chạy vòng lặp .Contains (), tỷ lệ này với x * y tệ hơn nhiều.


+1 cho thuật toán hiệu quả hơn. Ngay cả khi các danh sách hiện chưa được sắp xếp, sẽ hiệu quả hơn trước tiên là sắp xếp chúng và sau đó chạy thuật toán này.
Matt Boehm

Thời gian chạy sẽ không tỷ lệ thuận với max (kích thước (x), kích thước (y)) trong trường hợp xấu nhất chứ? Ví dụ: int [] x = {99,100}; int [] y = {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
Matt Boehm

Không bởi vì một khi bạn hoàn thành bộ nhỏ hơn, bạn có thể nối các phần tử còn lại từ bộ lớn hơn vì chúng đã được sắp xếp. Tôi nghĩ rằng quá trình này tương tự như Hợp nhất Sắp xếp.

3

Nếu có thể sắp xếp các mục của bạn thì có một cách nhanh hơn để làm điều này sau đó thực hiện tra cứu chính thành một hashtable hoặc b-tree. Mặc dù nếu các mặt hàng của bạn không thể sắp xếp, bạn thực sự không thể đặt chúng vào cây b.

Dù sao, nếu có thể sắp xếp cả hai danh sách thì đó chỉ là vấn đề đi theo danh sách tra cứu theo thứ tự.

Walk lookup list
   While items in check list <= lookup list item
     if check list item = lookup list item do something
   Move to next lookup list item

Vâng, rất đúng. Nếu bạn có hai danh sách được sắp xếp, bạn chỉ cần duyệt qua mỗi danh sách một lần.
chối

3

Nếu bạn đang sử dụng .Net 3.5, bạn có thể tạo mã sạch hơn bằng cách sử dụng:

foreach (Record item in LookupCollection.Intersect(LargeCollection))
{
  //dostuff
}

Tôi không có .Net 3.5 ở đây và vì vậy điều này chưa được kiểm tra. Nó dựa vào một phương pháp mở rộng. Không phải LookupCollection.Intersect(LargeCollection)là có lẽ không giống như LargeCollection.Intersect(LookupCollection)... cái sau có lẽ chậm hơn nhiều.

Giả định này Tra cứu là một HashSet


2

Nếu bạn không lo lắng về việc rít lên từng chút hiệu suất cuối cùng, đề xuất sử dụng Hashset hoặc tìm kiếm nhị phân là vững chắc. Các bộ dữ liệu của bạn không đủ lớn để điều này sẽ trở thành vấn đề 99%.

Nhưng nếu điều này chỉ là một trong hàng ngàn lần bạn sẽ làm điều này và hiệu suất là rất quan trọng (và được chứng minh là không thể chấp nhận được bằng cách sử dụng tìm kiếm Hashset / nhị phân), bạn chắc chắn có thể viết thuật toán của riêng mình để đưa các danh sách được sắp xếp thực hiện so sánh khi bạn đi. Mỗi danh sách sẽ được chuyển đi nhiều nhất một lần và trong các trường hợp bệnh lý sẽ không tệ (một khi bạn đã đi theo con đường này, bạn có thể thấy rằng sự so sánh, giả sử đó là một chuỗi hoặc giá trị không tách rời khác, sẽ là chi phí thực sự và tối ưu hóa đó sẽ là bước tiếp theo).

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.