2010-05-05 19 views
78

Dường như kiến ​​thức chung là các bảng băm có thể đạt được O (1), nhưng điều đó chưa bao giờ có ý nghĩa đối với tôi. Ai đó có thể vui lòng giải thích nó? Dưới đây là hai tình huống cần lưu ý:Bảng băm thực sự có thể là O (1)?

A. Giá trị là một int nhỏ hơn kích thước của bảng băm. Do đó, giá trị là giá trị băm của chính nó, do đó không có bảng băm. Nhưng nếu có, nó sẽ là O (1) và vẫn không hiệu quả.

B. Bạn phải tính giá trị băm của giá trị. Trong trường hợp này, thứ tự là O (n) cho kích thước của dữ liệu được tra cứu. Việc tra cứu có thể là O (1) sau khi bạn thực hiện công việc O (n), nhưng điều đó vẫn xuất hiện với O (n) trong mắt tôi.

Và trừ khi bạn có băm hoàn hảo hoặc bảng băm lớn, có thể có một số mục trên mỗi nhóm. Vì vậy, nó biến thành một tìm kiếm tuyến tính nhỏ tại một số điểm anyway.

Tôi nghĩ bảng băm là tuyệt vời, nhưng tôi không nhận được chỉ định O (1) trừ khi nó được cho là lý thuyết.

Wikipedia article for hash tables liên tục tham chiếu thời gian tra cứu liên tục và bỏ qua hoàn toàn chi phí của hàm băm. Đó có thực sự là một biện pháp công bằng không?


Edit: Để tóm tắt những gì tôi đã học:

  • Đó là về mặt kỹ thuật đúng bởi vì các hàm băm không cần phải sử dụng tất cả các thông tin trong khóa và do đó có thể là thời gian liên tục, và bởi vì một chiếc bàn đủ lớn có thể mang va chạm xuống gần thời gian không đổi.

  • Điều này đúng trong thực tế bởi vì theo thời gian nó chỉ hoạt động miễn là hàm băm và kích thước bảng được chọn để giảm thiểu xung đột, mặc dù điều đó thường có nghĩa là không sử dụng hàm băm thời gian cố định.

+25

Nó khấu hao (1), không phải O (1). – kennytm

+0

Hãy nhớ rằng O() là giới hạn cho một số lượng lớn các hoạt động. Trên 'trung bình' bạn sẽ không có nhiều va chạm - nó không cần thiết mà một hoạt động cá nhân không có va chạm. –

+0

Tùy thuộc vào việc thực hiện chuỗi, chuỗi có thể mang theo giá trị băm của chúng với chúng, vì vậy điều này sẽ không đổi. Vấn đề là, nó không liên quan đến sự phức tạp tra cứu hash. –

Trả lời

41

Bạn có hai biến ở đây, m và n, trong đó m là độ dài của đầu vào và n là số mục trong băm.

O (1) khẳng định hiệu suất tra cứu làm cho ít nhất hai giả định:

  • đối tượng của bạn có thể bình đẳng so với trong thời gian O (1) thời gian.
  • Sẽ có một vài va chạm băm.

Nếu đối tượng của bạn có kích thước thay đổi và kiểm tra bình đẳng yêu cầu xem xét tất cả các bit thì hiệu suất sẽ trở thành O (m). Hàm băm tuy nhiên không phải là O (m) - nó có thể là O (1). Không giống như một băm mật mã, một hàm băm để sử dụng trong một từ điển không phải xem xét từng bit trong đầu vào để tính toán giá trị băm. Việc triển khai miễn phí chỉ xem xét một số bit cố định.

Đối với đủ mục, số lượng mục sẽ lớn hơn số lượng băm có thể và sau đó bạn sẽ nhận được va chạm làm cho hiệu suất tăng trên O (1), ví dụ O (n) cho một danh sách liên kết đơn giản. hoặc O (n * m) nếu cả hai giả định là sai).

Trong thực tế, mặc dù yêu cầu O (1) trong khi sai về mặt kỹ thuật, là khoảng đúng cho nhiều tình huống trong thế giới thực và đặc biệt là những tình huống mà các giả định ở trên nắm giữ.

+4

Cũng như ở trên, nếu bạn đang sử dụng các đối tượng bất biến như các phím của bạn Java Strings, đã tính toán băm một lần, bạn có thể nhớ nó và không phải tính toán nó một lần nữa. Mặt khác, bạn thường không thể dựa vào hàm băm để biết hai khóa có bằng nhau không khi bạn đã tìm thấy nhóm thích hợp, vì vậy đối với các chuỗi bạn cần phải thực hiện tra cứu O (m) để tìm ra chúng có bằng nhau hay không. – JeremyP

+1

@JeremyP: Điểm tốt về so sánh bình đẳng O (m). Tôi đã bỏ lỡ điều đó - bài đăng được cập nhật. Cảm ơn! –

+0

Khiếu nại 'O (1)' là đúng nếu bạn băm 'int' hoặc một cái gì đó khác phù hợp với từ máy. Đó là lý thuyết mà lý thuyết băm nhất định giả định. –

3

Băm có kích thước cố định - tra cứu nhóm băm thích hợp là hoạt động chi phí cố định. Điều này có nghĩa rằng nó là O (1).

Tính toán băm không phải là một hoạt động đặc biệt tốn kém - chúng tôi không nói các hàm băm mật mã ở đây. Nhưng đó là bằng cách. Bản thân hàm băm không phụ thuộc vào số n của các phần tử; mặc dù nó có thể phụ thuộc vào kích thước của dữ liệu trong một phần tử, nhưng đây không phải là những gì n đề cập đến. Vì vậy, việc tính toán giá trị băm không phụ thuộc vào n và cũng là O (1).

+1

tra cứu nhóm băm là O (1). Nhưng định vị khóa bên phải, là một thủ tục O (n), trong đó n phụ thuộc vào số lần va chạm băm. –

+1

Vì vậy, trong 3 bước, tính toán băm, tìm các thùng, tìm kiếm các thùng, bước giữa là không đổi? Tìm kiếm xô thường là hằng số. Tính toán băm thường là một số đơn đặt hàng có độ lớn rẻ hơn các phương tiện tìm kiếm thùng khác. Nhưng điều đó có thực sự tăng thêm thời gian không? Trong một tìm kiếm chuỗi con ngây thơ, bạn sẽ nói O (n * m) cho hai độ dài, vậy tại sao chiều dài của khóa bị bỏ qua ở đây? – drawnonward

+0

tìm một khóa độ dài cố định chỉ là O (n) nếu danh sách của nó được sao lưu, bảng băm được sao lưu bằng cây cân bằng sẽ là O (log (n)) –

18

Bạn phải tính giá trị băm, vì vậy thứ tự là O (n) đối với kích thước của dữ liệu đang được tìm kiếm. Việc tra cứu có thể là O (1) sau khi bạn thực hiện công việc O (n), nhưng điều đó vẫn xuất hiện với O (n) trong mắt tôi.

Cái gì? Để băm một phần tử duy nhất có thời gian không đổi. Tại sao nó lại là cái gì khác? Nếu bạn đang chèn các thành phần n, thì có, bạn phải tính toán số băm n và mất thời gian tuyến tính ... để tìm kiếm một phần tử, bạn tính một băm duy nhất của những gì bạn đang tìm kiếm, sau đó tìm nhóm thích hợp với. Bạn không tính toán lại các băm của mọi thứ đã có trong bảng băm.

Và trừ khi bạn có băm hoàn hảo hoặc bảng băm lớn có thể có một số mục trên mỗi nhóm để nó biến thành một tìm kiếm tuyến tính nhỏ tại một số điểm.

Không nhất thiết. Các nhóm không nhất thiết phải là danh sách hoặc mảng, chúng có thể là bất kỳ loại vùng chứa nào, chẳng hạn như BST cân bằng. Điều đó có nghĩa là trường hợp xấu nhất O(log n). Nhưng đây là lý do tại sao điều quan trọng là phải chọn một hàm băm tốt để tránh đặt quá nhiều phần tử vào một nhóm. Như KennyTM đã chỉ ra, trung bình, bạn vẫn sẽ nhận được O(1) thời gian, ngay cả khi thỉnh thoảng bạn phải đào qua một cái xô.

Việc cắt giảm bảng băm tất nhiên là sự phức tạp về không gian. Bạn đang kinh doanh không gian cho thời gian, mà dường như là trường hợp thông thường trong khoa học máy tính.


Bạn đề cập đến việc sử dụng các chuỗi làm chìa khóa trong một trong các nhận xét khác của bạn. Bạn lo ngại về lượng thời gian cần để tính toán giá trị băm của một chuỗi, bởi vì nó bao gồm nhiều ký tự? Như một người khác chỉ ra một lần nữa, bạn không nhất thiết cần phải nhìn vào tất cả các ký tự để tính toán băm, mặc dù nó có thể tạo ra một hash tốt hơn nếu bạn đã làm. Trong trường hợp đó, nếu có trung bình m ký tự trong khóa của bạn và bạn đã sử dụng tất cả chúng để tính toán hàm băm của mình, thì tôi cho rằng bạn nói đúng, các tra cứu đó sẽ mất O(m). Nếu m >> n thì bạn có thể gặp sự cố. Bạn có lẽ sẽ tốt hơn với BST trong trường hợp đó. Hoặc chọn hàm băm rẻ hơn.

+0

bảng băm không sử dụng BST. BST không yêu cầu giá trị băm. Bản đồ và Bộ có thể được thực hiện dưới dạng BST. –

+3

@Nick: Eh? Không ... BST không yêu cầu giá trị băm ... đó là vấn đề. Chúng tôi giả định rằng tại thời điểm này, chúng tôi đã có một vụ va chạm (cùng một băm ... hoặc ít nhất là cùng một nhóm), vì vậy chúng tôi cần xem xét một yếu tố khác để tìm phần tử phù hợp, tức là giá trị thực tế. – mpen

+0

oh, tôi thấy quan điểm của bạn. Nhưng tôi không chắc chắn rằng trộn BST và băm đáng giá. Tại sao không chỉ sử dụng BST? –

2

Hashing là O (1) chỉ khi chỉ có số lượng khóa liên tục trong bảng và một số giả định khác được thực hiện. Nhưng trong những trường hợp như vậy, nó có lợi thế.

Nếu khóa của bạn có biểu diễn n bit, hàm băm của bạn có thể sử dụng 1, 2, ... n của các bit này.Suy nghĩ về hàm băm sử dụng 1 bit. Đánh giá là O (1) chắc chắn. Nhưng bạn chỉ phân vùng không gian chính thành 2. Vì vậy, bạn đang ánh xạ tới 2^(n-1) vào cùng một thùng. bằng cách sử dụng tìm kiếm BST, việc này sẽ thực hiện các bước n-1 để định vị một khóa cụ thể nếu gần đầy.

Bạn có thể mở rộng điều này để thấy rằng nếu hàm băm của bạn sử dụng K bit, kích thước thùng của bạn là 2^(n-k).

vì vậy hàm băm bit ==> không quá 2^K thùng hiệu quả ==> tối đa 2^(nK) phím bit cho mỗi bin ==> (nK) bước (BST) để giải quyết xung đột . Trên thực tế hầu hết các hàm băm ít hiệu quả hơn nhiều và cần/sử dụng nhiều hơn K bit để tạo ra các thùng 2^k. Vì vậy, ngay cả điều này là lạc quan.

Bạn có thể xem theo cách này - bạn sẽ cần ~ n bước để có thể phân biệt duy nhất một cặp khóa n bit trong trường hợp xấu nhất. Có thực sự không có cách nào để có được xung quanh giới hạn lý thuyết thông tin này, bảng băm hay không.

Tuy nhiên, đây không phải là cách thức/khi bạn sử dụng bảng băm!

Phân tích phức tạp giả định rằng đối với khóa n bit, bạn có thể có các phím O (2^n) trong bảng (ví dụ: 1/4 tất cả các khóa có thể). Nhưng hầu hết nếu không phải tất cả thời gian chúng tôi sử dụng bảng băm, chúng tôi chỉ có một số liên tục của các phím n-bit trong bảng. Nếu bạn chỉ muốn một số lượng khóa không đổi trong bảng, C là số tối đa của bạn, thì bạn có thể tạo thành bảng băm O (C), đảm bảo va chạm liên tục dự kiến ​​(với hàm băm tốt); và hàm băm sử dụng ~ logC của n bit trong khóa. Sau đó, mỗi truy vấn là O (logC) = O (1). Đây là cách mọi người khiếu nại "truy cập bảng băm là O (1)"/

Có một vài điều bắt đầu ở đây - trước tiên, nói rằng bạn không cần tất cả các bit chỉ có thể là thủ thuật thanh toán. Trước tiên, bạn không thể thực sự chuyển giá trị khóa cho hàm băm, vì điều đó sẽ di chuyển n bit trong bộ nhớ là O (n). Vì vậy, bạn cần phải làm ví dụ một tham chiếu đi qua. Nhưng bạn vẫn cần phải lưu trữ nó ở đâu đó đã là một hoạt động O (n); bạn chỉ không hóa đơn nó cho băm; bạn tính toán tổng thể nhiệm vụ không thể tránh điều này. Thứ hai, bạn làm băm, tìm thùng, và tìm thấy nhiều hơn 1 phím; chi phí của bạn phụ thuộc vào phương pháp phân giải của bạn - nếu bạn so sánh dựa trên (BST hoặc Danh sách), bạn sẽ có hoạt động O (n) (phím gọi lại là n-bit); nếu bạn làm băm 2, tốt, bạn có cùng một vấn đề nếu băm thứ 2 có va chạm. Vì vậy, O (1) không được đảm bảo 100% trừ khi bạn không có va chạm (bạn có thể cải thiện cơ hội bằng cách có một bảng với nhiều thùng hơn các phím, nhưng vẫn còn).

Cân nhắc giải pháp thay thế, ví dụ: BST, trong trường hợp này. có các khóa C, vì vậy một BST cân bằng sẽ là O (logC) theo chiều sâu, do đó, tìm kiếm có các bước O (logC). Tuy nhiên so sánh trong trường hợp này sẽ là một hoạt động O (n) ... do đó, nó xuất hiện băm là một lựa chọn tốt hơn trong trường hợp này.

0

Có hai cài đặt mà bạn có thể nhận được O (1) thời gian xấu nhất.

  1. Nếu thiết lập của bạn tĩnh, khi đó FKS băm sẽ giúp bạn có trường hợp xấu nhất O (1) đảm bảo. Nhưng như bạn đã chỉ ra, cài đặt của bạn không tĩnh.
  2. Nếu bạn sử dụng Cuckoo băm, sau đó truy vấn và xóa là O (1) trường hợp xấu nhất, nhưng chèn chỉ O (1) mong đợi. Cuckoo hashing hoạt động khá tốt nếu bạn có giới hạn trên trên tổng số lần chèn và đặt kích thước bảng lớn hơn khoảng 25%. O

sao chép từ here