Bản đồ băm C / C ++ hiệu suất siêu cao (bảng, từ điển) [đóng]


84

Tôi cần ánh xạ các khóa nguyên thủy (int, có thể dài) thành các giá trị struct trong cấu trúc dữ liệu bản đồ băm hiệu suất cao.

Chương trình của tôi sẽ có vài trăm bản đồ này và mỗi bản đồ nói chung sẽ có nhiều nhất vài nghìn mục nhập. Tuy nhiên, các bản đồ sẽ được "làm mới" hoặc "khuấy" liên tục; tưởng tượng việc xử lý hàng triệu adddeletetin nhắn trong một giây.

Thư viện nào trong C hoặc C ++ có cấu trúc dữ liệu phù hợp với trường hợp sử dụng này? Hoặc, bạn sẽ đề xuất xây dựng của riêng bạn như thế nào? Cảm ơn!


1
Bạn có cần xử lý tìm kiếm theo khóa vào dữ liệu của mình không?
Guillaume Lebourgeois

3
cập nhật hoặc truy xuất sẽ thường xuyên hơn? (thêm / xóa, hoặc đọc / cập nhật mà không thay đổi chìa khóa)
falstro

stackoverflow.com/questions/266206/… . Đây có thể là một nơi tốt để bắt đầu.
DumbCoder

2
@roe:Các thao tác thêm / xóa thường xuyên hơn nhiều (100 lần) so với thao tác get.
Haywood Jablomey

1
Sau bốn năm rưỡi, sẽ rất thú vị nếu biết điều gì phù hợp với nhu cầu của bạn nhất. Nếu không có câu trả lời hiện tại nào là thỏa đáng, bạn có thể viết câu trả lời của riêng mình và chấp nhận nó.
Walter Tross

Câu trả lời:


31

Tôi khuyên bạn nên dùng thử Google SparseHash (hoặc Google SparseHash-c11 phiên bản C11 ) và xem nó có phù hợp với nhu cầu của bạn không. Chúng có triển khai hiệu quả về bộ nhớ cũng như được tối ưu hóa cho tốc độ. Tôi đã thực hiện một điểm chuẩn cách đây khá lâu, đó là cách triển khai bảng băm tốt nhất hiện có về tốc độ (tuy nhiên có nhược điểm).


16
Bạn có thể giải thích rõ những hạn chế là gì không?
Haywood Jablomey

IIRC, đó là một vấn đề về bộ nhớ, khi xóa một phần tử, phần tử đó đã bị hủy nhưng bộ nhớ của nó vẫn còn sống (tôi đoán là dùng làm bộ nhớ đệm).
Scharron

4
@Haywood Jablomey: Hạn chế chính là nó yêu cầu bạn tách một hoặc hai giá trị (nếu bạn từng xóa phần tử) và không bao giờ sử dụng chúng. Trong một số trường hợp, điều này rất dễ thực hiện, ví dụ như int phủ định hoặc tương tự, nhưng trong các trường hợp khác thì không hoàn toàn như vậy.
doublep

3
Bạn có đứng trước đề xuất này hôm nay không?
einpoklum

11

Thư viện nào trong C hoặc C ++ có cấu trúc dữ liệu phù hợp với trường hợp sử dụng này? Hoặc, bạn sẽ đề xuất xây dựng của riêng bạn như thế nào? Cảm ơn!

Kiểm tra mảng LGPL'd Judy . Chưa bao giờ sử dụng bản thân mình, nhưng đã được quảng cáo cho tôi trong một vài dịp.

Bạn cũng có thể thử chuẩn các vùng chứa STL (std :: hash_map, v.v.). Tùy thuộc vào nền tảng / triển khai và điều chỉnh mã nguồn (phân bổ trước càng nhiều càng tốt, quản lý bộ nhớ động rất tốn kém) chúng có thể đủ hiệu quả.

Ngoài ra, nếu hiệu suất của giải pháp cuối cùng vượt trội hơn chi phí của giải pháp, bạn có thể cố gắng đặt hàng hệ thống có đủ RAM để đưa mọi thứ vào các mảng đơn giản. Hiệu suất truy cập theo chỉ mục là không thể đánh bại.

Các thao tác thêm / xóa thường xuyên hơn nhiều (100 lần) so với thao tác get.

Điều đó gợi ý rằng bạn có thể muốn tập trung vào việc cải thiện các thuật toán trước. Nếu dữ liệu chỉ được ghi, không được đọc, thì tại sao phải viết chúng?


11

Chỉ cần sử dụng boost::unordered_map(hoặc tr1vv) theo mặc định. Sau đó lập hồ sơ mã của bạn và xem mã đó có phải là nút cổ chai hay không. Chỉ khi đó tôi mới đề nghị phân tích chính xác các yêu cầu của bạn để tìm người thay thế nhanh hơn.


15
Nó là. VS2013 std::unordered_mapđang chiếm hơn 90% toàn bộ thời gian thực hiện của tôi, mặc dù tôi chỉ sử dụng bản đồ cho một phần tương đối nhỏ của quá trình xử lý.
Cameron




2

Trước tiên, hãy kiểm tra xem các giải pháp hiện có như libmemcache có phù hợp với nhu cầu của bạn không.

Nếu không ...

Bản đồ băm dường như là câu trả lời chắc chắn cho yêu cầu của bạn. Nó cung cấp o (1) tra cứu dựa trên các phím. Ngày nay, hầu hết các thư viện STL đều cung cấp một số loại băm. Vì vậy, hãy sử dụng cái được cung cấp bởi nền tảng của bạn.

Khi phần đó được thực hiện, bạn phải kiểm tra giải pháp để xem liệu thuật toán băm mặc định có đủ hiệu suất tốt cho nhu cầu của bạn hay không.

Nếu không, bạn nên khám phá một số thuật toán băm nhanh tốt được tìm thấy trên mạng

  1. số nguyên tố cũ tốt nhân lên
  2. http://www.azillionmonkeys.com/qed/hash.html
  3. http://burtleburtle.net/bob/
  4. http://code.google.com/p/google-sparsehash/

Nếu điều này chưa đủ tốt, bạn có thể tự mình cuộn một mô-đun băm để khắc phục sự cố mà bạn đã gặp với các vùng chứa STL mà bạn đã thử nghiệm và một trong các thuật toán băm ở trên. Hãy chắc chắn để đăng kết quả ở đâu đó.

Ồ và điều thú vị là bạn có nhiều bản đồ ... có lẽ bạn có thể đơn giản hóa bằng cách đặt khóa của mình dưới dạng num 64 bit với các bit cao được sử dụng để phân biệt bản đồ đó thuộc về bản đồ nào và thêm tất cả các cặp giá trị khóa vào một hàm băm khổng lồ. Tôi đã thấy các hàm băm có hàng trăm nghìn ký hiệu hoạt động hoàn toàn tốt trên thuật toán băm số nguyên tố cơ bản khá tốt.

Bạn có thể kiểm tra xem giải pháp đó hoạt động như thế nào so với hàng trăm bản đồ .. tôi nghĩ điều đó có thể tốt hơn từ quan điểm lập hồ sơ bộ nhớ ... vui lòng đăng kết quả ở đâu đó nếu bạn thực hiện bài tập này

Tôi tin rằng ngoài thuật toán băm, nó có thể là việc thêm / xóa liên tục bộ nhớ (có thể tránh được không?) Và hồ sơ sử dụng bộ nhớ cache cpu có thể quan trọng hơn đối với hiệu suất của ứng dụng của bạn

chúc may mắn


2

Hãy thử các bảng băm từ Mẫu vùng chứa khác . Tốc độ của nó closed_hash_maptương đương với tốc độ của Google dense_hash_map, nhưng dễ sử dụng hơn (không hạn chế các giá trị có sẵn) và cũng có một số đặc quyền khác.


2

Tôi sẽ đề nghị uthash . Chỉ cần bao gồm #include "uthash.h"sau đó thêm a UT_hash_handlevào cấu trúc và chọn một hoặc nhiều trường trong cấu trúc của bạn để đóng vai trò là khóa. Một từ về hiệu suất ở đây .


1

http://incise.org/hash-table-benchmarks.html gcc có một triển khai rất tốt. Tuy nhiên, hãy nhớ rằng nó phải tôn trọng một quyết định tiêu chuẩn rất tệ:

Nếu xảy ra sự cố lại, tất cả các trình vòng lặp đều bị vô hiệu, nhưng các tham chiếu và con trỏ đến các phần tử riêng lẻ vẫn hợp lệ. Nếu không có rehash thực sự xảy ra, không có thay đổi.

http://www.cplusplus.com/reference/unordered_map/unordered_map/rehash/

Điều này có nghĩa là về cơ bản tiêu chuẩn nói rằng việc triển khai PHẢI dựa trên các danh sách được liên kết. Nó ngăn chặn địa chỉ mở có hiệu suất tốt hơn.

Tôi nghĩ rằng google thưa thớt đang sử dụng địa chỉ mở, mặc dù trong các tiêu chuẩn này, chỉ có phiên bản dày đặc hơn đối thủ. Tuy nhiên, phiên bản thưa thớt hơn hẳn mọi đối thủ về mức sử dụng bộ nhớ. (ngoài ra nó không có bất kỳ bình nguyên nào, số phần tử wrt đường thẳng thuần túy)


1
Xem thêm điều này , thảo luận về cách giao diện nhóm cũng yêu cầu chuỗi. Điểm về tài liệu tham khảo là rất tốt. Thật hấp dẫn để tranh luận và nói rằng đó là một đảm bảo hữu ích, nhưng trong nhiều trường hợp, chúng tôi chỉ muốn tham chiếu để tránh tra cứu lại các phần tử và lý do thông thường là vì tra cứu quá chậm ... điều này sẽ không xảy ra nếu không phải giữ cho các tham chiếu hợp lệ và do đó có thể sử dụng địa chỉ mở! Vì vậy, nó có vẻ hơi gà và trứng. Điều này trích dẫn đề xuất năm 2003, thảo luận rõ ràng về sự lựa chọn.
underscore_d
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.