2010-02-08 30 views
24

Tôi đang làm việc với một bộ lớn (5-20 triệu) của các khóa chuỗi (chiều dài trung bình 10 ký tự) cần lưu trữ trong một trong cấu trúc dữ liệu bộ nhớ hỗ trợ các hoạt động sau đây trong thời gian liên tục hoặc gần thời gian liên tục:Cần bộ nhớ hiệu quả để lưu trữ tấn chuỗi (là: Thực hiện HAT-Trie trong java)

// Returns true if the input is present in the container, false otherwise 
public boolean contains(String input) 

HashMap Java đang chứng tỏ là hơn thỏa đáng như xa như thông là có liên quan nhưng chiếm nhiều bộ nhớ. Tôi đang tìm một giải pháp đó là bộ nhớ hiệu quả và vẫn hỗ trợ một thông lượng đó là phong nha (so sánh với hoặc gần như tốt như băm).

Tôi không quan tâm đến thời gian chèn/xóa. Trong ứng dụng của tôi, tôi sẽ chỉ thực hiện chèn (chỉ vào thời điểm khởi động) và sau đó sẽ chỉ truy vấn cấu trúc dữ liệu bằng cách sử dụng phương thức contains cho tuổi thọ của ứng dụng.

Tôi đọc cấu trúc dữ liệu HAT-Trie gần nhất với nhu cầu của tôi. Tôi tự hỏi nếu có một thư viện có một thực hiện.

Các đề xuất khác với con trỏ để triển khai được chào đón.

Cảm ơn bạn.

+2

Tôi đoán mọi cơ sở hạ tầng khác sẽ sử dụng nhiều bộ nhớ, nếu được triển khai trong Java. – ebo

+1

@ebo Không nếu triển khai bên dưới sử dụng các ký tự chars/char. Không cần phải tồn tại đối tượng String đầu vào. Nhiệm vụ nói chung nên sử dụng bộ nhớ ít hơn. – hashable

+0

Câu hỏi rất thú vị. –

Trả lời

12

Trie có vẻ như là một ý tưởng rất tốt cho các ràng buộc của bạn.

A "suy nghĩ bên ngoài hộp" thay thế:

Nếu bạn có thể đủ khả năng một số khả năng trả lời "có mặt" cho một chuỗi mà vắng mặt

EDIT: nếu bạn có thể đủ khả năng dương tính giả, sử dụng một Bloom filter theo đề xuất của WizardOfOdds trong các ý kiến.

Đối với k = 1, bộ lọc Bloom giống như bảng băm không có khóa: mỗi "nhóm" chỉ đơn giản là một boolean cho biết nếu có ít nhất một đầu vào có cùng giá trị băm. Nếu 1% dương tính giả là chấp nhận được, bảng băm của bạn có thể là nhỏ như khoảng 100 * 20 triệu bit hoặc khoảng 200 MiB. Đối với 1 trong 1000 dương tính giả, 2GiB.

Sử dụng nhiều hàm băm thay vì một hàm có thể cải thiện tỷ lệ dương giả cho cùng một lượng bit.

+3

@Pascaul Cuoq: Tôi không downvoting bạn nhưng bạn đang tái phát minh ra một bánh xe ở đây, có lẽ ít hiệu quả hơn những gì tồn tại. Tôi không biết nơi bạn đang nhận được số của bạn từ nhưng có một cấu trúc dữ liệu được biết đến cho phép một% dương tính giả, nó được gọi là một "Bloom Filter". Một bộ lọc nở hoa cho 200 triệu mục nhập với một dương tính giả chấp nhận được 1% sẽ mất 154 MB. – SyntaxT3rr0r

+0

Trên thực tế, 23MB cho 20 triệu mục làm áp phích gốc được chỉ định. Nhưng tất nhiên chúng tôi đã không được cho biết dương tính giả là OK ... –

+0

@WizardOfOdds Cảm ơn con trỏ. Tôi đã đề xuất thực sự là một bộ lọc nở hoa ngây thơ (k = 1). –

2

Để biết hiệu quả về không gian, tra cứu O (log (n)) và mã đơn giản, hãy thử tìm kiếm nhị phân trên một mảng ký tự. 20 triệu phím có chiều dài trung bình 10 tạo 200 triệu ký tự: 400MB nếu bạn cần 2 byte/char; 200MB nếu bạn có thể lấy đi với 1. Trên đầu trang này, bạn cần bằng cách nào đó đại diện cho ranh giới giữa các phím trong mảng. Nếu bạn có thể đặt trước một ký tự phân cách, đó là một cách; nếu không, bạn có thể sử dụng một mảng song song của khoảng bù int.

Biến thể đơn giản nhất sẽ sử dụng một chuỗi các chuỗi, với chi phí không gian cao từ chi phí cho mỗi đối tượng. Nó phải vẫn đánh bại một hashtable trong không gian hiệu quả, mặc dù không phải là ấn tượng.

+0

@Darius Bacon: toàn bộ từ điển sử dụng tra cứu O (log n) có thể được lưu trữ bằng cách sử dụng ít hơn 10 bit cho mỗi chuỗi (!!!). Có thật không. Ít hơn 10 bit, tôi đã thực hiện nó. Ngoài ra còn có các thuật toán nén cao cho từ điển sử dụng 12 bit cho mỗi từ cũng cho phép tra cứu gợi ý nhanh. Nhưng câu hỏi ban đầu được hỏi một cách rõ ràng về một O (1) chứa, không phải là O (log n), vì vậy tôi không thể đề xuất loại cấu trúc dữ liệu "nén cao, 10 bit mỗi từ" như một câu trả lời. – SyntaxT3rr0r

+1

Vâng, tôi đã chỉ ra những từ điển nén như vậy trong câu trả lời của tôi cho một câu hỏi khác. Tôi sẽ không thử bất cứ thứ gì lạ mắt như gợi ý đầu tiên của tôi ở đây - nó sẽ mất nhiều công sức để làm nó nhanh, nếu nó có thể làm được, phải không? Và câu hỏi được hỏi cho * gần * liên tục thời gian; cho dù điều này là gần đủ sẽ phải được lên đến poster ban đầu. –

+0

(Kịch bản này của một hashtable chạy vào bộ nhớ giới hạn nhận được thay đổi để tìm kiếm nhị phân đã diễn ra trước khi trong cuộc sống công việc của tôi, trên thực tế.Các lập trình viên cơ sở hơn những người chạy vào vấn đề này được vẽ ra một giải pháp phức tạp, nhưng tìm kiếm nhị phân làm việc tốt Ngẫu nhiên tôi đã giới thiệu bộ lọc Bloom vào một phần khác của cùng một dự án ... nó giống như chuẩn bị cho việc bình luận về vấn đề stackoverflow này.) –

4

Google sẽ hiển thị bài đăng trên blog theo số HAT tries in Java. Nhưng tôi không thấy làm thế nào điều này sẽ giải quyết vấn đề của bạn trực tiếp: cấu trúc là một trie nông trên tiền tố của các phím, với lá là hashtables giữ hậu tố của tất cả các phím với tiền tố nhất định. Vì vậy, trong tổng số, bạn có rất nhiều hashtables lưu trữ tất cả các phím trong một hiện tại của bạn hashtable lớn (có lẽ tiết kiệm một vài byte cho mỗi phím tổng thể vì các tiền tố phổ biến). Dù bằng cách nào, bạn cần một hashtable không gian hiệu quả hơn so với Java mặc định, hoặc chi phí cho mỗi đối tượng sẽ đánh bạn chỉ là xấu.Vì vậy, tại sao không bắt đầu với một lớp hashtable chuyên biệt cho các phím chuỗi chỉ, nếu bạn đi tuyến đường này, và lo lắng về phần trie chỉ khi nó vẫn có vẻ đáng giá sau đó?

2

Tương tự như trie là cây tìm kiếm bậc ba, nhưng cây tìm kiếm bậc ba có lợi thế là sử dụng ít bộ nhớ hơn. Bạn có thể đọc về cây tìm kiếm ba năm here, herehere. Một trong những giấy tờ chính về chủ đề của Jon Bentley và Robert Sedgewick là here. Nó cũng nói về việc sắp xếp các chuỗi nhanh chóng, vì vậy đừng bỏ qua điều đó.

+0

"Cây ba lá lớn hơn đáng kể so với bản đồ băm hoặc thiết kế cây nhị phân" (http: //abc.se/~re/code/tst/tst_docs/perf_notes.html) – ArtemGr

Các vấn đề liên quan