2012-03-03 39 views
21

Tôi muốn băm một chuỗi có độ dài lên đến 30. Điều gì sẽ là ý tưởng tốt nhất để làm điều đó nếu thời gian là mối quan tâm của tôi. Chức năng này sẽ được gọi hơn 100 triệu lần. Hiện tại tôi đang sử dụng đoạn mã sau,Một hàm băm nhanh cho chuỗi trong C#

static UInt64 CalculateHash(string read, bool lowTolerance) 
{ 
    UInt64 hashedValue = 0; 
    int i = 0; 
    while (i < read.Length) 
    { 
     hashedValue += read.ElementAt(i) * (UInt64)Math.Pow(31, i); 
     if (lowTolerance) i += 2; 
     else i++; 
    } 
    return hashedValue; 
} 
+5

Có lý do gì khiến phương thức 'Object.GetHashCode()' không hoạt động đối với bạn không? Có vẻ như bạn đang thực hiện khá nhiều khái niệm tương tự. –

+3

Bất kỳ thứ gì không sử dụng * toán học dấu chấm động * sẽ nhanh hơn. –

+0

GetHashCode không thể tồn tại, vì vậy nếu anh ta cần lưu trữ mã băm vào cơ sở dữ liệu, nó không hữu ích. Sau đó, một lần nữa, không phải là điều này. Sử dụng của bạn là gì? Bạn chỉ cần băm chuỗi khi chạy, hay bạn cần làm gì với Hash? Adler-32 có thể là một lựa chọn nếu bạn cần lưu trữ nó và không chạy quá nhiều va chạm. –

Trả lời

37
static UInt64 CalculateHash(string read) 
{ 
    UInt64 hashedValue = 3074457345618258791ul; 
    for(int i=0; i<read.Length; i++) 
    { 
     hashedValue += read[i]; 
     hashedValue *= 3074457345618258799ul; 
    } 
    return hashedValue; 
} 

Đây là một hash Knuth. Bạn cũng có thể sử dụng Jenkins.

+1

Theo thử nghiệm của riêng tôi, chức năng này không đạt được thác lở. YMMV. – Fantius

+0

@Fantius: Bạn có thể thử sử dụng '11400714819306691477ul' thay thế không. (Đối với cả hai giá trị.) –

+2

Tệ hơn. Nhưng tôi nên định lượng bản báo cáo ban đầu của mình. Toggling một bit trên các kết quả đầu vào trong khoảng 49,40% của các bit đầu ra toggling (sử dụng hằng số ban đầu của bạn), đó là MUCH tốt hơn so với các chức năng dựa trên Bernstein. Đó có thể là đủ tốt cho hầu hết các công dụng. Nhưng, ví dụ, SuperFastHash (http://landman-code.blogspot.com/2009/02/c-superfasthash-and-murmurhash2.html) cho tôi 50,02%. Và Murmur2 trên cùng một trang đang cho tôi 50,04%. – Fantius

1

Tôi đã chơi với triển khai Paul Hsieh, và dường như được nhanh chóng với sự va chạm nhỏ (cho các kịch bản của tôi anyway)

+0

Vâng xin lỗi, đọc câu hỏi khác nhau lần đầu tiên. Đã chỉnh sửa! – skub

+0

hi có vẻ tốt hơn. Tôi sẽ thực hiện nó trong C# và sẽ thấy. –

1

Để tăng tốc độ triển khai của bạn, cuộc gọi (UInt64)Math.Pow(31, i) sẽ được thay thế bằng tra cứu: tính toán trước bảng 30 quyền hạn đầu tiên của 31 và sử dụng nó khi chạy. Kể từ khi giới hạn về chiều dài là 30, bạn chỉ cần 31 yếu tố:

private static unsigned long[] Pow31 = new unsigned long[31]; 

static HashCalc() { 
    Pow31[0] = 1; 
    for (int i = 1 ; i != Pow31.Length ; i++) { 
     Pow31[i] = 31*Pow31[i-1]; 
    } 
} 

// In your hash function... 
hashedValue += read.ElementAt(i) * Pow31[i]; 
+0

Tôi sẽ không chắc để tìm kiếm bảng nhanh hơn phép nhân số nguyên. – CodesInChaos

+0

@CodeInChaos Nó chắc chắn nhanh hơn 'Math.Pow (31, i)'. Ngoài ra tôi cần một phép nhân bổ sung khi 'i' tăng lên 2 bên trong một điều kiện, vì vậy tôi sẽ thử tra cứu trước. – dasblinkenlight

6

Trước hết, hãy cân nhắc sử dụng GetHashCode().

Một cải tiến đơn giản về việc thực hiện hiện tại của bạn:

static UInt64 CalculateHash(string read, bool lowTolerance) 
{ 
    UInt64 hashedValue = 0; 
    int i = 0; 
    ulong multiplier = 1; 
    while (i < read.Length) 
    { 
     hashedValue += read[i] * multiplier; 
     multiplier *= 37; 
     if (lowTolerance) i += 2; 
     else i++; 
    } 
    return hashedValue; 
} 

Nó tránh được việc tính toán dấu chấm động đắt tiền, và các chi phí của ElementAt.

Btw (UInt64)Math.Pow(31, i) không hoạt động tốt đối với các chuỗi dài hơn. Làm tròn điểm nổi sẽ dẫn đến một hệ số 0 cho các ký tự vượt quá 15 hoặc hơn.

+0

Hệ số phải bắt đầu với giá trị lớn hơn 256 hoặc số này phá vỡ khủng khiếp nếu byte đầu tiên nhỏ. –

+0

@DavidSchwartz Một nguyên tố lớn hơn chắc chắn là tốt hơn, nhưng phá vỡ khủng khiếp là một chút quá mức. – CodesInChaos

+0

Nếu hàm băm 64 bit có nhiều đầu vào 2 byte va chạm, IMO sẽ phá vỡ khủng khiếp. (Nhưng với chức năng của OP bắt đầu với mức độ nào, có thể tiêu chuẩn của tôi quá cao.) –

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