2009-11-03 28 views
5

Tôi phải thừa nhận rằng chỉ có một sự hiểu biết sơ bộ về cách HashTables hoạt động, mặc dù từ những gì tôi biết ít có vẻ khá đơn giản. Câu hỏi của tôi chỉ là điều này: có vẻ như sự khôn ngoan thông thường là sử dụng các loại giá trị đơn giản, cơ bản như số nguyên cho các khóa trong HashTable. Tuy nhiên, các chuỗi cũng thường được sử dụng, mặc dù trong nhiều ngôn ngữ chúng được triển khai như các kiểu tham chiếu. Những gì tôi cảm thấy nói chung là không phải là được khuyến khích sử dụng các loại tham chiếu phức tạp; Tôi đoán điều này là bởi vì làm như vậy sẽ đòi hỏi một hàm băm chậm hơn? Nhưng sau đó tại sao các chuỗi thường được sử dụng? Sau khi tất cả, không phải là một chuỗi bên trong một mảng char [] (một lần nữa, trong hầu hết các ngôn ngữ)?Các loại được chấp nhận để sử dụng làm khóa trong HashTable

Cuối cùng, loại giá trị nào thường được coi là lựa chọn "tốt nhất" (hoặc thậm chí là "chấp nhận được") để sử dụng làm khóa trong HashTable? Và có bất kỳ sự lựa chọn thường được sử dụng mà thực sự được coi là "xấu" (như dây, có thể)?

Trả lời

1

tốt nhất hash keys là những

  1. Có tốt (như trong collisions thấp) băm (xem Object.GetHashCode cho .NET, Object.hashcode cho Java)
  2. Có so sánh nhanh chóng (ví khi có va chạm băm) .

Tất cả những gì đã nói, tôi nghĩ Strings là khóa băm tốt trong hầu hết các trường hợp, vì có nhiều triển khai băm xuất sắc cho Strings.

3

Miễn là hàm băm phù hợp được cung cấp, tất cả các loại sẽ hoạt động như khóa. Hãy nhớ rằng sau khi tất cả một bảng băm chỉ là một mảng tuyến tính. Hàm băm lấy một khóa của một kiểu nhất định và tính toán một chỉ mục trong mảng bảng băm (được gọi là bucket), nơi giá trị được lưu trữ (có một số vấn đề với các va chạm).

Vì vậy, phần khó nhất thực sự là tìm hàm băm. Tất nhiên nó phải có các thuộc tính nhất định, như tính toán đơn giản, hỗn loạn (các khóa gần như giống hệt nhau nên được ánh xạ tới các thùng bảng băm hoàn toàn khác nhau), xác định (cùng một khóa có nghĩa là cùng một bảng băm), tính đồng nhất (tất cả các khóa có thể được ánh xạ đều đến các nhóm), hoặc tính từ (tất cả các nhóm của bảng băm nên được sử dụng).

Dường như việc xác định hàm như vậy cho các loại đơn giản như số nguyên càng dễ dàng hơn.

+0

sai! vấn đề thực sự là sự biến đổi quan trọng! – Gyom

+0

Điều đó thực sự đúng. Tuy nhiên nó là một definiton những gì các phím được coi là bằng nhau và đó không phải là. – spa

4

Hầu hết các triển khai chuỗi, trong khi chúng có thể xuất hiện dưới dạng loại tham chiếu trong môi trường được quản lý, việc triển khai của chúng thường là loại không thay đổi.

Chức năng hàm băm là gì nó ánh xạ một số lượng lớn các trạng thái lên một số tiểu bang nhỏ hơn.

Đó là lý do tại sao băm chuỗi là tốt để thử nghiệm chuỗi bình đẳng. Bạn có thể ánh xạ giá trị tới một chỉ mục của một mảng và tra cứu một số thông tin về giá trị đó rất nhanh chóng. Bạn không cần phải so sánh mọi nhân vật với mọi nhân vật khác trong mỗi chuỗi khác. Và bạn có thể nói về cùng một thứ về mọi thứ. Đó là tất cả về việc giảm, hoặc lấy dấu vân tay một số byte tùy ý theo cách nào đó hữu ích. Đây là nơi mà các cuộc thảo luận về loại khóa bạn sử dụng trong một bảng băm trở nên không hợp lệ, bởi vì nó là ánh xạ của giá trị đó vào một không gian trạng thái nhỏ hơn và cách nó được sử dụng trong nội bộ. Một số nguyên thường là phần cứng thân thiện, nhưng 32-bit không thực sự là một không gian lớn và va chạm có khả năng trong không gian đó cho đầu vào tùy ý.Cuối cùng, khi bạn sử dụng bảng băm, chi phí tính giá trị băm không liên quan so với thời gian cần để so sánh mọi giá trị với mọi giá trị khác ở mọi vị trí có thể khác (giả sử rằng băm của bạn bảng chứa hàng trăm mục).

+0

Tôi hiểu rằng hàm băm hoạt động bằng cách ánh xạ một giá trị lớn (có khả năng) đến một không gian nhỏ hơn, nhưng tốc độ của hàm băm cũng không phụ thuộc vào kích thước của đầu vào của nó? Đó là lý do tại sao tôi cho rằng nó thường không khuyến khích sử dụng các loại tham chiếu lớn như các khóa. Nếu đó không phải là trường hợp, tuy nhiên, sau đó tôi tự hỏi tại sao điều này sẽ được nản lòng sau khi tất cả (có lẽ đó là vì các nhà phát triển cần phải thực hiện chức năng băm hiệu quả của riêng mình?). –

+0

Như tôi đã nói, nhiều môi trường được quản lý thực hiện các chuỗi như các loại bất biến. Và khi bạn có loại bất biến, mã băm không cần phải được tính mỗi lần bởi vì giá trị là hằng số (khi được tạo). Thông thường, bạn sẽ chỉ phải trả chi phí sản xuất mã băm, một lần, cho mỗi chuỗi duy nhất. ví dụ. Thời gian chạy .NET duy trì một nhóm chuỗi bên trong để thực hiện việc này. Tuy nhiên, chi phí sản xuất mã băm từ một chuỗi không xác định là có, nhưng chi phí có liên quan đến độ dài của chuỗi được sử dụng làm khóa không phải kích thước của bộ sưu tập (hoặc bảng băm). –

+0

Điều này khá phản đối với tôi. Bạn có nói rằng, nếu tôi thêm một mục vào một HashTable, sau đó sau đó đi để lấy mục đó bằng khóa, thời gian chạy sẽ kỳ diệu biết mã băm cho khóa đó mà không cần phải thực hiện hàm băm? Làm sao có thể? –

1

Nếu bạn đã sử dụng một loại phức tạp như một chìa khóa sau đó:

  • Nó sẽ là khó khăn cho việc thực hiện bảng băm để mục nhóm vào xô để thu hồi nhanh chóng; làm thế nào nó sẽ quyết định làm thế nào để nhóm một loạt các băm vào một xô?
  • Bảng băm có thể cần phải có kiến ​​thức thân mật về loại để chọn một nhóm.
  • Có nguy cơ về các thuộc tính của đối tượng thay đổi, dẫn đến các mục kết thúc bằng các nhóm không đúng. Các băm phải không thay đổi.

Số nguyên thường được sử dụng vì chúng dễ phân tách thành các dải tương ứng với nhóm, chúng là loại giá trị và do đó không thay đổi và chúng khá dễ tạo.

5

Nó không phải là một vấn đề của chuỗi so số nguyên, hoặc giá trị so với tham chiếu, nhưng phím có thể thay đổi so với các phím không thay đổi. Miễn là các phím không thay đổi (và do đó giá trị băm của chúng không bao giờ thay đổi), chúng có thể lập chỉ mục một bảng băm. Ví dụ, các chuỗi trong Java là không thay đổi và do đó hoàn toàn phù hợp với các khóa có thể bắt đầu.

Nhân tiện, nếu một kiểu dữ liệu đủ đủ để luôn được truyền theo giá trị (như vô hướng), thì tất nhiên nó sẽ là OK.

Nhưng bây giờ hãy tưởng tượng rằng bạn sử dụng loại có thể thay đổi; nếu bạn cho tôi một tham chiếu đến một trong các đối tượng này như là một khóa, tôi sẽ tính toán giá trị băm của nó và sau đó đặt nó vào một trong các nhóm hashtable của tôi. Nhưng khi bạn sửa đổi đối tượng, tôi sẽ không có cách nào để được thông báo; và đối tượng hiện có thể nằm trong nhóm không đúng (nếu giá trị băm của nó khác nhau).

Hy vọng điều này sẽ hữu ích.

+0

Đây là một câu trả lời rất hữu ích; nhưng tôi vẫn tự hỏi nếu có một số loại nào đó "tốt hơn" để sử dụng như là chìa khóa hơn những người khác. Ví dụ, giả sử tôi đã định nghĩa một lớp thực sự không thay đổi và sẽ tồn tại với cùng một mã băm cho toàn bộ sự tồn tại của nó. Có phải nó hoàn toàn tốt đẹp để sử dụng như một chìa khóa, hoặc nó vẫn sẽ tốt hơn để sử dụng một cái gì đó giống như một số nguyên (vì lý do hiệu suất)? Dường như với tôi giống như câu trả lời đầy đủ, toàn diện có thể là sự kết hợp của bạn (các khóa phải là loại bất biến) và các loại spa (các loại được sử dụng làm khóa nên có hàm băm hiệu quả) ... –

+0

@Dan: một bảng băm cụ thể cần để lưu trữ những gì cần lưu trữ. Nếu bạn đang duy trì bộ nhớ cache trên web, bạn đang lưu trữ nội dung cho URL. Khóa phải là một URL, nó không thể là một số nguyên, bởi vì bạn không tìm kiếm các số nguyên. Rõ ràng nhanh hơn là "tốt hơn", nhưng "làm những gì tôi muốn từ từ" luôn luôn "tốt hơn" hơn "làm điều gì đó thực sự nhanh nhưng hoàn toàn vô dụng" :-) –

+0

Điều quan trọng cần lưu ý là không có gì sai khi sử dụng loại lớp có thể thay đổi dưới dạng khóa băm-bàn nếu mục đích của khóa là * xác định * một đối tượng cụ thể. Ví dụ, trong .net, 'System.Windows.Forms.Form' là một loại có thể thay đổi (với các thuộc tính như vị trí, vv có thể thay đổi bất kỳ lúc nào) nhưng có thể sử dụng một hashtable để liên kết các biểu mẫu với cái gì khác. Lưu ý rằng một bảng như vậy sẽ luôn coi hai tham chiếu đến các biểu mẫu khác nhau là không bằng nhau, ngay cả khi tất cả các thuộc tính của chúng khác với danh tính của chúng đã xảy ra để khớp. – supercat

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