Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Nói chung, bạn sẽ sử dụng yếu tố độc đáo nhất trong hồ sơ người dùng của bạn. Và điều này thường có nghĩa là hệ thống nói chung có tên người dùng hoặc ID duy nhất cho mỗi bản ghi (người dùng), được đảm bảo là duy nhất. Tên người dùng hoặc ID sẽ là khóa duy nhất cho bản ghi. Vì điều này được thực thi bởi chính hệ thống, ví dụ bằng khóa tự động trong bảng cơ sở dữ liệu, bạn có thể chắc chắn rằng không có va chạm.

Do đó, khóa duy nhất đó phải là chìa khóa trong bản đồ của bạn để cho phép bạn tìm bản ghi người dùng.

Tuy nhiên, nếu vì một lý do nào đó, bạn không có quyền truy cập vào khóa Guranteed-to-be-Unique như vậy, bạn chắc chắn có thể tạo một hàm băm từ bản ghi (như được mô tả bởi bạn) và sử dụng bất kỳ thuật toán bảng băm nào Lưu trữ các yếu tố với các phím có thể va chạm. Trong trường hợp đó, bạn không tránh va chạm, nhưng bạn chỉ cần đối phó với nó.

Một thuật toán nhanh chóng và thường được sử dụng cho điều đó diễn ra như sau: Sử dụng băm trên bản ghi để tạo khóa, như bạn đã làm. Chìa khóa này có khả năng không phải là duy nhất. Bây giờ lưu trữ một danh sách các bản ghi tại vị trí được chỉ định bởi khóa. Chúng tôi gọi những danh sách đó 'xô'. Để lưu trữ một phần tử mới, băm nó và sau đó nối nó vào danh sách được lưu trữ tại vị trí đó (thêm nó vào xô). Để tìm một phần tử, băm nó, hãy tìm mục, sau đó tìm kiếm tuần tự thông qua danh sách/xô tại vị trí đó để tìm mục bạn muốn.

Đây là một ví dụ:

mymap[123] = [ {'name':'John','age':27}, {'name':'Bob','age':19} ]
mymap[678] = [ {'name':'Frank','age':29} ]

Trong ví dụ, bạn có bảng băm của bạn (được thực hiện thông qua một dict). Bạn có giá trị khóa băm 678, trong đó một mục được lưu trữ trong xô. Sau đó, bạn có giá trị khóa băm 123, nhưng có một vụ va chạm: cả mục 'John' và 'Bob' đều có giá trị băm này. Không có vấn đề, bạn tìm thấy xô được lưu trữ tại mymap [123] và lặp lại nó để tìm giá trị.

Đây là một triển khai linh hoạt và rất phổ biến của các bản đồ băm, không yêu cầu phân bổ lại hoặc các biến chứng khác. Nó được mô tả ở nhiều nơi, ví dụ ở đây: https://www.cs.aockland.ac.nz/~jmor159/plds210/hash_tables.html (trong Chương 8.3.1).

Hiệu suất nói chung chỉ trở thành một vấn đề khi bạn có rất nhiều va chạm (khi danh sách cho mỗi thùng thực sự dài). Một cái gì đó bạn sẽ tránh với một chức năng băm tốt.

Tuy nhiên: ví dụ: một ID duy nhất thực sự cho hồ sơ của bạn, được thực thi bởi cơ sở dữ liệu chẳng hạn, có lẽ vẫn là cách tiếp cận ưa thích.

Trong các phần trước, chúng tôi đã có thể cải thiện các thuật toán tìm kiếm của mình bằng cách tận dụng thông tin về nơi các mục được lưu trữ trong bộ sưu tập đối với nhau. Ví dụ, bằng cách biết rằng một danh sách đã được đặt hàng, chúng ta có thể tìm kiếm trong thời gian logarit bằng cách sử dụng tìm kiếm nhị phân. Trong phần này, chúng tôi sẽ cố gắng tiến thêm một bước bằng cách xây dựng cấu trúc dữ liệu có thể được tìm kiếm trong thời gian \ (o (1) \). Khái niệm này được gọi là băm.\(O(1)\) time. This concept is referred to as hashing.

Để làm điều này, chúng ta sẽ cần biết nhiều hơn về nơi các mục có thể ở đâu khi chúng ta đi tìm chúng trong bộ sưu tập. Nếu mọi mục là nơi cần có, thì tìm kiếm có thể sử dụng một so sánh duy nhất để khám phá sự hiện diện của một mục. Tuy nhiên, chúng ta sẽ thấy rằng đây thường không phải là trường hợp.

Một bảng băm là một tập hợp các mặt hàng được lưu trữ theo cách để dễ dàng tìm thấy chúng sau này. Mỗi vị trí của bảng băm, thường được gọi là khe, có thể giữ một mục và được đặt tên bởi một giá trị số nguyên bắt đầu từ 0. Ví dụ: chúng ta sẽ có một khe có tên 0, một khe có tên 1, một khe có tên 2, và do đó trên. Ban đầu, bảng băm không chứa các mục để mọi khe trống đều trống. Chúng tôi có thể triển khai bảng băm bằng cách sử dụng một danh sách với mỗi phần tử được khởi tạo thành giá trị Python đặc biệt None. Hình 4 cho thấy một bảng băm có kích thước \ (m = 11 \). Nói cách khác, có các khe m trong bảng, được đặt tên là 0 đến 10.hash table is a collection of items which are stored in such a way as to make it easy to find them later. Each position of the hash table, often called a slot, can hold an item and is named by an integer value starting at 0. For example, we will have a slot named 0, a slot named 1, a slot named 2, and so on. Initially, the hash table contains no items so every slot is empty. We can implement a hash table by using a list with each element initialized to the special Python value None. Figure 4 shows a hash table of size \(m=11\). In other words, there are m slots in the table, named 0 through 10.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 4: Bảng băm với 11 khe trống

Ánh xạ giữa một mục và khe nơi mục đó thuộc về bảng băm được gọi là hàm băm. Hàm băm sẽ lấy bất kỳ mục nào trong bộ sưu tập và trả về một số nguyên trong phạm vi tên khe, giữa 0 đến M-1. Giả sử rằng chúng ta có tập hợp các mục số nguyên 54, 26, 93, 17, 77 và 31. Chức năng băm đầu tiên của chúng ta, đôi khi được gọi là phương pháp còn lại, chỉ cần một mục và chia nó cho kích thước bảng, trả lại phần còn lại là giá trị băm của nó (\ (h (item) = item \% 11 \)). Bảng 4 đưa ra tất cả các giá trị băm cho các mục ví dụ của chúng tôi. Lưu ý rằng phương pháp còn lại này (số học modulo) thường sẽ có mặt ở một số dạng trong tất cả các hàm băm, vì kết quả phải nằm trong phạm vi của tên khe.hash function. The hash function will take any item in the collection and return an integer in the range of slot names, between 0 and m-1. Assume that we have the set of integer items 54, 26, 93, 17, 77, and 31. Our first hash function, sometimes referred to as the “remainder method,” simply takes an item and divides it by the table size, returning the remainder as its hash value (\(h(item)=item \% 11\)). Table 4 gives all of the hash values for our example items. Note that this remainder method (modulo arithmetic) will typically be present in some form in all hash functions, since the result must be in the range of slot names.

Bảng 4: Hàm băm đơn giản sử dụng phần còn lại

Mục

Giá trị băm

54

10

26

4

93

5

17

6

77

0

31

9

Khi các giá trị băm đã được tính toán, chúng ta có thể chèn từng mục vào bảng băm ở vị trí được chỉ định như trong Hình 5. Lưu ý rằng 6 trong số 11 vị trí hiện đang bị chiếm. Điều này được gọi là hệ số tải và thường được ký hiệu là \ (\ lambda = \ frac {numberOfItems} {patablesize} \). Đối với ví dụ này, \ (\ lambda = \ frac {6} {11} \).Figure 5. Note that 6 of the 11 slots are now occupied. This is referred to as the load factor, and is commonly denoted by \(\lambda = \frac {numberofitems}{tablesize}\). For this example, \(\lambda = \frac {6}{11}\).

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 5: Bảng băm với sáu mục

Bây giờ khi chúng tôi muốn tìm kiếm một mục, chúng tôi chỉ cần sử dụng hàm băm để tính tên khe cho mục và sau đó kiểm tra bảng băm để xem nó có mặt không. Hoạt động tìm kiếm này là \ (o (1) \), vì một khoảng thời gian không đổi là cần thiết để tính toán giá trị băm và sau đó chỉ mục bảng băm tại vị trí đó. Nếu mọi thứ là nơi cần có, chúng tôi đã tìm thấy một thuật toán tìm kiếm thời gian liên tục.\(O(1)\), since a constant amount of time is required to compute the hash value and then index the hash table at that location. If everything is where it should be, we have found a constant time search algorithm.

Bạn có thể đã thấy rằng kỹ thuật này sẽ chỉ hoạt động nếu mỗi mục ánh xạ đến một vị trí duy nhất trong bảng băm. Ví dụ: nếu mục 44 là mục tiếp theo trong bộ sưu tập của chúng tôi, nó sẽ có giá trị băm là 0 (\ (44 \% 11 == 0 \)). Vì 77 cũng có giá trị băm là 0, chúng tôi sẽ gặp vấn đề. Theo hàm băm, hai hoặc nhiều mục sẽ cần phải ở trong cùng một vị trí. Điều này được gọi là một vụ va chạm (nó cũng có thể được gọi là một cuộc đụng độ trên mạng). Rõ ràng, va chạm tạo ra một vấn đề cho kỹ thuật băm. Chúng tôi sẽ thảo luận chi tiết về chúng sau.\(44 \% 11 == 0\)). Since 77 also had a hash value of 0, we would have a problem. According to the hash function, two or more items would need to be in the same slot. This is referred to as a collision (it may also be called a “clash”). Clearly, collisions create a problem for the hashing technique. We will discuss them in detail later.

6.5.1. Chức năng băm CôngHash Functions¶

Đưa ra một bộ sưu tập các mục, một hàm băm có thể ánh xạ từng mục thành một khe duy nhất được gọi là một hàm băm hoàn hảo. Nếu chúng ta biết các mục và bộ sưu tập sẽ không bao giờ thay đổi, thì có thể xây dựng một hàm băm hoàn hảo (tham khảo các bài tập để biết thêm về các hàm băm hoàn hảo). Thật không may, với một bộ sưu tập các mặt hàng tùy ý, không có cách nào có hệ thống để xây dựng một hàm băm hoàn hảo. May mắn thay, chúng tôi không cần chức năng băm để trở nên hoàn hảo để vẫn đạt được hiệu quả hiệu suất.perfect hash function. If we know the items and the collection will never change, then it is possible to construct a perfect hash function (refer to the exercises for more about perfect hash functions). Unfortunately, given an arbitrary collection of items, there is no systematic way to construct a perfect hash function. Luckily, we do not need the hash function to be perfect to still gain performance efficiency.

Một cách để luôn có một hàm băm hoàn hảo là tăng kích thước của bảng băm để mỗi giá trị có thể có trong phạm vi vật phẩm có thể được cung cấp. Điều này đảm bảo rằng mỗi mục sẽ có một khe duy nhất. Mặc dù điều này là thực tế cho một số lượng nhỏ các mặt hàng, nhưng nó không khả thi khi số lượng các mặt hàng có thể lớn. Ví dụ: nếu các mục là số an sinh xã hội gồm chín chữ số, phương pháp này sẽ yêu cầu gần một tỷ vị trí. Nếu chúng tôi chỉ muốn lưu trữ dữ liệu cho một lớp 25 sinh viên, chúng tôi sẽ lãng phí một lượng bộ nhớ khổng lồ.

Mục tiêu của chúng tôi là tạo ra một hàm băm nhằm giảm thiểu số lượng va chạm, rất dễ tính toán và phân phối đều các mục trong bảng băm. Có một số cách phổ biến để mở rộng phương pháp phần còn lại đơn giản. Chúng tôi sẽ xem xét một vài trong số họ ở đây.

Phương pháp gấp để xây dựng các hàm băm bắt đầu bằng cách chia mục thành các phần có kích thước bằng nhau (phần cuối cùng có thể không có kích thước bằng nhau). Những mảnh này sau đó được thêm vào với nhau để cung cấp giá trị băm kết quả. Ví dụ: nếu mục của chúng tôi là số điện thoại 436-555-4601, chúng tôi sẽ lấy các chữ số và chia chúng thành các nhóm 2 (43,65,55,46,01). Sau khi bổ sung, \ (43+65+55+46+01 \), chúng ta sẽ nhận được 210. Nếu chúng ta cho rằng bảng băm của chúng ta có 11 khe cắm, thì chúng ta cần thực hiện bước bổ sung chia cho 11 và giữ phần còn lại. Trong trường hợp này \ (210 \ \%\ 11 \) là 1, do đó, số điện thoại 436-555-4601 băm vào khe 1. Một số phương pháp gấp đi thêm một bước và đảo ngược mọi mảnh khác trước khi thêm. Đối với ví dụ trên, chúng ta nhận được \ (43+56+55+64+01 = 219 \) cho \ (219 \ \%\ 11 = 10 \).folding method for constructing hash functions begins by dividing the item into equal-size pieces (the last piece may not be of equal size). These pieces are then added together to give the resulting hash value. For example, if our item was the phone number 436-555-4601, we would take the digits and divide them into groups of 2 (43,65,55,46,01). After the addition, \(43+65+55+46+01\), we get 210. If we assume our hash table has 11 slots, then we need to perform the extra step of dividing by 11 and keeping the remainder. In this case \(210\ \%\ 11\) is 1, so the phone number 436-555-4601 hashes to slot 1. Some folding methods go one step further and reverse every other piece before the addition. For the above example, we get \(43+56+55+64+01 = 219\) which gives \(219\ \%\ 11 = 10\).

Một kỹ thuật số khác để xây dựng hàm băm được gọi là phương pháp giữa hình vuông. Đầu tiên chúng tôi vuông vật phẩm, và sau đó trích xuất một số phần của các chữ số kết quả. Ví dụ: nếu mục là 44, trước tiên chúng ta sẽ tính toán \ (44 ^{2} = 1.936 \). Bằng cách trích xuất hai chữ số giữa, 93 và thực hiện bước còn lại, chúng tôi nhận được 5 (\ (93 \ \%\ 11 \)). Bảng 5 cho thấy các mục theo cả phương thức còn lại và phương thức giữa hình vuông. Bạn nên xác minh rằng bạn hiểu cách các giá trị này được tính toán.mid-square method. We first square the item, and then extract some portion of the resulting digits. For example, if the item were 44, we would first compute \(44 ^{2} = 1,936\). By extracting the middle two digits, 93, and performing the remainder step, we get 5 (\(93\ \%\ 11\)). Table 5 shows items under both the remainder method and the mid-square method. You should verify that you understand how these values were computed.

Bảng 5: So sánh các phương pháp còn lại và giữa vuông

Mục

Phần còn lại

Mid-Square

54

10

3

26

4

7

93

5

9

17

6

8

77

0

4

31

9

6

Chúng tôi cũng có thể tạo các hàm băm cho các mục dựa trên ký tự như chuỗi. Từ Cat Cat có thể được coi là một chuỗi các giá trị thứ tự.

>>> ord('c')
99
>>> ord('a')
97
>>> ord('t')
116

Sau đó, chúng ta có thể lấy ba giá trị thứ tự này, thêm chúng lên và sử dụng phương pháp còn lại để có được giá trị băm (xem Hình 6). Liệt kê 1 hiển thị một hàm gọi là hash có một chuỗi và kích thước bảng và trả về giá trị băm trong phạm vi từ 0 đến ________ 10-1.Figure 6). Listing 1 shows a function called hash that takes a string and a table size and returns the hash value in the range from 0 to

>>> ord('c')
99
>>> ord('a')
97
>>> ord('t')
116
0-1.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 6: Băm một chuỗi bằng cách sử dụng các giá trị thứ tự

Liệt kê 1

def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize

Thật thú vị khi lưu ý rằng khi sử dụng hàm băm này, các anagram sẽ luôn được cung cấp cùng một giá trị băm. Để khắc phục điều này, chúng ta có thể sử dụng vị trí của nhân vật làm trọng lượng. Hình 7 cho thấy một cách có thể để sử dụng giá trị vị trí làm yếu tố trọng số. Việc sửa đổi chức năng hash được để lại như một bài tập.Figure 7 shows one possible way to use the positional value as a weighting factor. The modification to the hash function is left as an exercise.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 7: Băm một chuỗi bằng cách sử dụng các giá trị thứ tự với trọng số

Bạn có thể nghĩ ra một số cách bổ sung để tính toán các giá trị băm cho các mục trong một bộ sưu tập. Điều quan trọng cần nhớ là hàm băm phải có hiệu quả để nó không trở thành phần chi phối của quá trình lưu trữ và tìm kiếm. Nếu hàm băm quá phức tạp, thì việc tính toán tên khe sẽ trở nên nhiều hơn so với việc thực hiện tìm kiếm tuần tự hoặc nhị phân cơ bản như được mô tả trước đó. Điều này sẽ nhanh chóng đánh bại mục đích băm.

6.5.2. Nghị quyết va chạmCollision Resolution¶

Bây giờ chúng tôi trở lại vấn đề va chạm. Khi hai mục băm vào cùng một khe, chúng ta phải có một phương pháp có hệ thống để đặt mục thứ hai trong bảng băm. Quá trình này được gọi là giải quyết va chạm. Như chúng tôi đã nêu trước đó, nếu hàm băm là hoàn hảo, các va chạm sẽ không bao giờ xảy ra. Tuy nhiên, vì điều này thường là không thể, độ phân giải va chạm trở thành một phần rất quan trọng của băm.collision resolution. As we stated earlier, if the hash function is perfect, collisions will never occur. However, since this is often not possible, collision resolution becomes a very important part of hashing.

Một phương pháp để giải quyết các va chạm nhìn vào bảng băm và cố gắng tìm một khe mở khác để giữ vật phẩm gây ra vụ va chạm. Một cách đơn giản để làm điều này là bắt đầu ở vị trí giá trị băm ban đầu và sau đó di chuyển theo cách tuần tự qua các vị trí cho đến khi chúng ta gặp phải khe cắm đầu tiên trống. Lưu ý rằng chúng ta có thể cần quay lại vị trí đầu tiên (một cách tròn) để che toàn bộ bảng băm. Quá trình giải quyết va chạm này được gọi là địa chỉ mở ở chỗ nó cố gắng tìm vị trí hoặc địa chỉ mở tiếp theo trong bảng băm. Bằng cách truy cập một cách có hệ thống từng vị trí một lần một lần, chúng tôi đang thực hiện một kỹ thuật địa chỉ mở gọi là thăm dò tuyến tính.open addressing in that it tries to find the next open slot or address in the hash table. By systematically visiting each slot one at a time, we are performing an open addressing technique called linear probing.

Hình 8 cho thấy một tập hợp các mục số nguyên mở rộng theo hàm băm phương pháp phần còn lại đơn giản (54,26,93,17,77,31,44,55,20). Bảng 4 ở trên cho thấy các giá trị băm cho các mục gốc. Hình 5 cho thấy nội dung ban đầu. Khi chúng ta cố gắng đặt 44 vào khe 0, xảy ra va chạm. Theo thăm dò tuyến tính, chúng tôi trông tuần tự, khe cắm, cho đến khi chúng tôi tìm thấy một vị trí mở. Trong trường hợp này, chúng tôi tìm thấy Slot 1. shows an extended set of integer items under the simple remainder method hash function (54,26,93,17,77,31,44,55,20). Table 4 above shows the hash values for the original items. Figure 5 shows the original contents. When we attempt to place 44 into slot 0, a collision occurs. Under linear probing, we look sequentially, slot by slot, until we find an open position. In this case, we find slot 1.

Một lần nữa, 55 nên đi trong khe 0 nhưng phải được đặt trong Slot 2 vì đây là vị trí mở tiếp theo. Giá trị cuối cùng của 20 băm đến khe 9. Vì Slot 9 đã đầy, chúng tôi bắt đầu thực hiện thăm dò tuyến tính. Chúng tôi ghé thăm các khe 10, 0, 1 và 2 và cuối cùng tìm thấy một khe trống ở vị trí 3.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 8: Độ phân giải va chạm với thăm dò tuyến tính

Khi chúng tôi đã xây dựng một bảng băm bằng địa chỉ mở và thăm dò tuyến tính, điều cần thiết là chúng tôi sử dụng các phương pháp tương tự để tìm kiếm các mục. Giả sử chúng tôi muốn tra cứu mục 93. Khi chúng tôi tính toán giá trị băm, chúng tôi nhận được 5. Nhìn vào Slot 5 tiết lộ 93 và chúng tôi có thể trả về

>>> ord('c')
99
>>> ord('a')
97
>>> ord('t')
116
2. Nếu chúng ta đang tìm kiếm 20 thì sao? Bây giờ giá trị băm là 9 và SLOT 9 hiện đang giữ 31. Chúng tôi không thể đơn giản trả lại
>>> ord('c')
99
>>> ord('a')
97
>>> ord('t')
116
3 vì chúng tôi biết rằng có thể có va chạm. Bây giờ chúng tôi buộc phải thực hiện tìm kiếm tuần tự, bắt đầu từ vị trí 10, tìm kiếm cho đến khi chúng tôi tìm thấy mục 20 hoặc chúng tôi tìm thấy một khe trống.

Một bất lợi cho thăm dò tuyến tính là xu hướng phân cụm; Các mục trở thành nhóm trong bảng. Điều này có nghĩa là nếu nhiều va chạm xảy ra ở cùng giá trị băm, một số vị trí xung quanh sẽ được lấp đầy bởi độ phân giải thăm dò tuyến tính. Điều này sẽ có tác động đến các mục khác đang được chèn vào, như chúng ta đã thấy khi chúng ta cố gắng thêm mục 20 ở trên. Một cụm các giá trị băm đến 0 phải được bỏ qua để cuối cùng tìm thấy một vị trí mở. Cụm này được hiển thị trong Hình 9.clustering; items become clustered in the table. This means that if many collisions occur at the same hash value, a number of surrounding slots will be filled by the linear probing resolution. This will have an impact on other items that are being inserted, as we saw when we tried to add the item 20 above. A cluster of values hashing to 0 had to be skipped to finally find an open position. This cluster is shown in Figure 9.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 9: Một cụm các mục cho khe 0¶

Một cách để đối phó với phân cụm là mở rộng kỹ thuật thăm dò tuyến tính để thay vì nhìn tuần tự cho khe mở tiếp theo, chúng tôi bỏ qua các khe, từ đó phân phối đều hơn các mục đã gây va chạm. Điều này sẽ có khả năng làm giảm sự phân cụm xảy ra. Hình 10 cho thấy các mục khi độ phân giải va chạm được thực hiện với đầu dò cộng với 3 cộng đồng. Điều này có nghĩa là một khi xảy ra va chạm, chúng ta sẽ xem xét mọi vị trí thứ ba cho đến khi chúng ta tìm thấy một vị trí trống.Figure 10 shows the items when collision resolution is done with a “plus 3” probe. This means that once a collision occurs, we will look at every third slot until we find one that is empty.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 10: Độ phân giải va chạm bằng cách sử dụng cộng với 3 cộng đồng

Tên chung cho quá trình tìm kiếm một vị trí khác sau khi va chạm đang được thử lại. Với đầu dò tuyến tính đơn giản, hàm phục hồi là \ (newhashvalue = rehash (OldHashValue) \) trong đó \ (rehash (pos) = (pos + 1) \% sizeoftable \). Có thể định nghĩa Rehash 3 cộng đồng có thể được định nghĩa là \ (rehash (pos) = (pos+3) \% sizeoftable \). Nói chung, \ (rehash (pos) = (pos + bỏ qua) \% sizeftable \). Điều quan trọng cần lưu ý là kích thước của Skip Skip phải sao cho tất cả các vị trí trong bảng cuối cùng sẽ được truy cập. Nếu không, một phần của bảng sẽ không được sử dụng. Để đảm bảo điều này, người ta thường cho rằng kích thước bảng là số nguyên tố. Đây là lý do chúng tôi đã sử dụng 11 trong các ví dụ của chúng tôi.rehashing. With simple linear probing, the rehash function is \(newhashvalue = rehash(oldhashvalue)\) where \(rehash(pos) = (pos + 1) \% sizeoftable\). The “plus 3” rehash can be defined as \(rehash(pos) = (pos+3) \% sizeoftable\). In general, \(rehash(pos) = (pos + skip) \% sizeoftable\). It is important to note that the size of the “skip” must be such that all the slots in the table will eventually be visited. Otherwise, part of the table will be unused. To ensure this, it is often suggested that the table size be a prime number. This is the reason we have been using 11 in our examples.

Một biến thể của ý tưởng thăm dò tuyến tính được gọi là thăm dò bậc hai. Thay vì sử dụng giá trị bỏ qua không đổi trên mạng, chúng tôi sử dụng hàm thử lại tăng giá trị băm lên 1, 3, 5, 7, 9, v.v. Điều này có nghĩa là nếu giá trị băm đầu tiên là H, các giá trị liên tiếp là \ (h+1 \), \ (h+4 \), \ (h+9 \), \ (h+16 \), v.v. . Nói chung, tôi sẽ là i^2 \ (rehash (pos) = (h + i^2) \). Nói cách khác, thăm dò bậc hai sử dụng một điểm bỏ qua bao gồm các hình vuông hoàn hảo liên tiếp. Hình 11 cho thấy các giá trị ví dụ của chúng tôi sau khi chúng được đặt bằng kỹ thuật này.quadratic probing. Instead of using a constant “skip” value, we use a rehash function that increments the hash value by 1, 3, 5, 7, 9, and so on. This means that if the first hash value is h, the successive values are \(h+1\), \(h+4\), \(h+9\), \(h+16\), and so on. In general, the i will be i^2 \(rehash(pos) = (h + i^2)\). In other words, quadratic probing uses a skip consisting of successive perfect squares. Figure 11 shows our example values after they are placed using this technique.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 11: Độ phân giải va chạm với thăm dò bậc hai

Một phương pháp thay thế để xử lý vấn đề va chạm là cho phép mỗi khe chứa một tham chiếu đến một bộ sưu tập (hoặc chuỗi) của các mục. Chuỗi cho phép nhiều mục tồn tại tại cùng một vị trí trong bảng băm. Khi các vụ va chạm xảy ra, vật phẩm vẫn được đặt trong khe thích hợp của bảng băm. Khi ngày càng có nhiều vật phẩm băm vào cùng một vị trí, khó khăn trong việc tìm kiếm vật phẩm trong bộ sưu tập tăng lên. Hình 12 cho thấy các mục khi chúng được thêm vào bảng băm sử dụng chuỗi để giải quyết các va chạm.Chaining allows many items to exist at the same location in the hash table. When collisions happen, the item is still placed in the proper slot of the hash table. As more and more items hash to the same location, the difficulty of searching for the item in the collection increases. Figure 12 shows the items as they are added to a hash table that uses chaining to resolve collisions.

Hướng dẫn how do you handle collisions in a hash table in python? - làm thế nào để bạn xử lý các va chạm trong một bảng băm trong python?

Hình 12: Độ phân giải va chạm với chuỗi

Khi chúng tôi muốn tìm kiếm một mục, chúng tôi sử dụng hàm băm để tạo vị trí nơi nó nên cư trú. Vì mỗi khe chứa một bộ sưu tập, chúng tôi sử dụng một kỹ thuật tìm kiếm để quyết định xem mặt hàng có mặt hay không. Ưu điểm là trung bình có khả năng có ít mục hơn trong mỗi vị trí, vì vậy việc tìm kiếm có lẽ hiệu quả hơn. Chúng tôi sẽ xem xét phân tích cho băm ở cuối phần này.

Tự kiểm tra

    Q-1: Trong bảng băm có kích thước 13 vị trí chỉ số nào sẽ có hai khóa sau bản đồ? 27, 130

  • 1, 10
  • Cẩn thận sử dụng bộ phận không số nguyên modulo
  • 13, 0
  • Đừng chia cho hai, sử dụng toán tử modulo.
  • 1, 0
  • 27 % 13 == 1 và 130 % 13 == 0
  • 2, 3
  • Sử dụng toán tử modulo

    Q-2: Giả sử bạn được cung cấp bộ khóa sau để chèn vào bảng băm chứa chính xác 11 giá trị: 113, 117, 97, 100, 114, 108, 116, 105, 99 Điều nào sau đây thể hiện tốt nhất nội dung của bảng băm sau khi tất cả các khóa đã được chèn bằng cách sử dụng thăm dò tuyến tính?

  • 100, __, __, 113, 114, 105, 116, 117, 97, 108, 99
  • Có vẻ như bạn có thể đã làm modulo 2 arithmentic. Bạn cần sử dụng kích thước bảng Hash làm giá trị modulo.
  • 99, 100, __, 113, 114, __, 116, 117, 105, 97, 108
  • Sử dụng đầu dò số học và tuyến tính modulo 11 cho các giá trị này
  • 100, 113, 117, 97, 14, 108, 116, 105, 99, __, __
  • Có vẻ như bạn đang sử dụng số học Modulo 10, sử dụng kích thước bảng.
  • 117, 114, 108, 116, 105, 99, __, __, 97, 100, 113
  • Hãy cẩn thận để sử dụng modulo không phân chia số nguyên.

6.5.3. Thực hiện kiểu dữ liệu trừu tượng >>> ord('c') 99 >>> ord('a') 97 >>> ord('t') 116 4Implementing the >>> ord('c') 99 >>> ord('a') 97 >>> ord('t') 116 4 Abstract Data Type¶

Một trong những bộ sưu tập Python hữu ích nhất là từ điển. Hãy nhớ lại rằng một từ điển là một loại dữ liệu kết hợp nơi bạn có thể lưu trữ các cặp DATA Key. Khóa được sử dụng để tra cứu giá trị dữ liệu liên quan. Chúng tôi thường đề cập đến ý tưởng này như một bản đồ.map.

Kiểu dữ liệu trừu tượng bản đồ được định nghĩa như sau. Cấu trúc là một bộ sưu tập liên kết không có thứ tự giữa khóa và giá trị dữ liệu. Các khóa trong bản đồ đều là duy nhất để có mối quan hệ một-một giữa khóa và giá trị. Các hoạt động được đưa ra dưới đây.

  • >>> ord('c')
    99
    >>> ord('a')
    97
    >>> ord('t')
    116
    
    5 Tạo một bản đồ mới, trống. Nó trả về một bộ sưu tập bản đồ trống.

  • >>> ord('c')
    99
    >>> ord('a')
    97
    >>> ord('t')
    116
    
    6 Thêm một cặp giá trị khóa mới vào bản đồ. Nếu khóa đã có trong bản đồ thì hãy thay thế giá trị cũ bằng giá trị mới.

  • >>> ord('c')
    99
    >>> ord('a')
    97
    >>> ord('t')
    116
    
    7 Cho một khóa, trả về giá trị được lưu trữ trong bản đồ hoặc None nếu không.

  • >>> ord('c')
    99
    >>> ord('a')
    97
    >>> ord('t')
    116
    
    9 Xóa cặp giá trị khóa khỏi bản đồ bằng cách sử dụng câu lệnh của Mẫu
    def hash(astring, tablesize):
        sum = 0
        for pos in range(len(astring)):
            sum = sum + ord(astring[pos])
    
        return sum%tablesize
    
    0.

  • def hash(astring, tablesize):
        sum = 0
        for pos in range(len(astring)):
            sum = sum + ord(astring[pos])
    
        return sum%tablesize
    
    1 Trả về số lượng các cặp giá trị khóa được lưu trữ trong bản đồ.

  • def hash(astring, tablesize):
        sum = 0
        for pos in range(len(astring)):
            sum = sum + ord(astring[pos])
    
        return sum%tablesize
    
    2 Trả về
    >>> ord('c')
    99
    >>> ord('a')
    97
    >>> ord('t')
    116
    
    2 cho một câu lệnh của Mẫu
    def hash(astring, tablesize):
        sum = 0
        for pos in range(len(astring)):
            sum = sum + ord(astring[pos])
    
        return sum%tablesize
    
    4, nếu khóa đã cho trong bản đồ,
    >>> ord('c')
    99
    >>> ord('a')
    97
    >>> ord('t')
    116
    
    3 khác.

Một trong những lợi ích tuyệt vời của từ điển là thực tế là một chìa khóa, chúng ta có thể tìm kiếm giá trị dữ liệu liên quan rất nhanh. Để cung cấp khả năng tra cứu nhanh này, chúng tôi cần một triển khai hỗ trợ tìm kiếm hiệu quả. Chúng tôi có thể sử dụng một danh sách với tìm kiếm tuần tự hoặc nhị phân nhưng sẽ tốt hơn nữa khi sử dụng bảng băm như được mô tả ở trên kể từ khi tìm kiếm một mục trong bảng băm có thể tiếp cận hiệu suất \ (o (1) \).\(O(1)\) performance.

Trong liệt kê 2, chúng tôi sử dụng hai danh sách để tạo một lớp

def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
6 thực hiện kiểu dữ liệu trừu tượng bản đồ. Một danh sách, được gọi là
def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
7, sẽ giữ các mục chính và danh sách song song, được gọi là
def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
8, sẽ giữ các giá trị dữ liệu. Khi chúng tôi tìm kiếm một khóa, vị trí tương ứng trong danh sách dữ liệu sẽ giữ giá trị dữ liệu được liên kết. Chúng tôi sẽ coi danh sách chính là bảng băm bằng cách sử dụng các ý tưởng được trình bày trước đó. Lưu ý rằng kích thước ban đầu cho bảng băm đã được chọn là 11. Mặc dù điều này là tùy ý, điều quan trọng là kích thước là một số nguyên tố để thuật toán độ phân giải va chạm có thể hiệu quả nhất có thể.Listing 2 we use two lists to create a
def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
6 class that implements the Map abstract data type. One list, called
def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
7, will hold the key items and a parallel list, called
def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
8, will hold the data values. When we look up a key, the corresponding position in the data list will hold the associated data value. We will treat the key list as a hash table using the ideas presented earlier. Note that the initial size for the hash table has been chosen to be 11. Although this is arbitrary, it is important that the size be a prime number so that the collision resolution algorithm can be as efficient as possible.

Liệt kê 2

class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size

def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
9 thực hiện phương pháp phần còn lại đơn giản. Kỹ thuật độ phân giải va chạm là thăm dò tuyến tính với chức năng Rehash 1 cộng với 1. Hàm
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
0 (xem Danh sách 3) giả định rằng cuối cùng sẽ có một khe trống trừ khi khóa đã có trong
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
1. Nó tính toán giá trị băm ban đầu và nếu khe đó không trống, hãy lặp lại hàm
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
2 cho đến khi một khe trống xảy ra. Nếu một khe cắm không trống đã chứa khóa, giá trị dữ liệu cũ sẽ được thay thế bằng giá trị dữ liệu mới. Đối phó với tình huống không còn khe trống là một bài tập.Listing 3) assumes that there will eventually be an empty slot unless the key is already present in the
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
1. It computes the original hash value and if that slot is not empty, iterates the
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
2 function until an empty slot occurs. If a nonempty slot already contains the key, the old data value is replaced with the new data value. Dealing with the situation where there are no empty slots left is an exercise.

Liệt kê 3

def put(self,key,data):
  hashvalue = self.hashfunction(key,len(self.slots))

  if self.slots[hashvalue] == None:
    self.slots[hashvalue] = key
    self.data[hashvalue] = data
  else:
    if self.slots[hashvalue] == key:
      self.data[hashvalue] = data  #replace
    else:
      nextslot = self.rehash(hashvalue,len(self.slots))
      while self.slots[nextslot] != None and \
                      self.slots[nextslot] != key:
        nextslot = self.rehash(nextslot,len(self.slots))

      if self.slots[nextslot] == None:
        self.slots[nextslot]=key
        self.data[nextslot]=data
      else:
        self.data[nextslot] = data #replace

def hashfunction(self,key,size):
     return key%size

def rehash(self,oldhash,size):
    return (oldhash+1)%size

Tương tự như vậy, hàm

class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
3 (xem Danh sách 4) bắt đầu bằng cách tính toán giá trị băm ban đầu. Nếu giá trị không nằm trong vị trí ban đầu,
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
2 được sử dụng để xác định vị trí tiếp theo có thể. Lưu ý rằng dòng 15 đảm bảo rằng tìm kiếm sẽ chấm dứt bằng cách kiểm tra để đảm bảo rằng chúng tôi chưa quay lại vị trí ban đầu. Nếu điều đó xảy ra, chúng tôi đã cạn kiệt tất cả các vị trí có thể và mặt hàng không được có mặt.Listing 4) begins by computing the initial hash value. If the value is not in the initial slot,
class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None] * self.size
        self.data = [None] * self.size
2 is used to locate the next possible position. Notice that line 15 guarantees that the search will terminate by checking to make sure that we have not returned to the initial slot. If that happens, we have exhausted all possible slots and the item must not be present.

Các phương pháp cuối cùng của lớp

def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
6 cung cấp chức năng từ điển bổ sung. Chúng tôi quá tải các phương thức __getItem__ và __setItem__ để cho phép truy cập bằng cách sử dụng`` [] ``. Điều này có nghĩa là một khi
def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
6 đã được tạo, toán tử chỉ mục quen thuộc sẽ có sẵn. Chúng tôi để lại các phương pháp còn lại như các bài tập.

Liệt kê 4

 1def get(self,key):
 2  startslot = self.hashfunction(key,len(self.slots))
 3
 4  data = None
 5  stop = False
 6  found = False
 7  position = startslot
 8  while self.slots[position] != None and  \
 9                       not found and not stop:
10     if self.slots[position] == key:
11       found = True
12       data = self.data[position]
13     else:
14       position=self.rehash(position,len(self.slots))
15       if position == startslot:
16           stop = True
17  return data
18
19def __getitem__(self,key):
20    return self.get(key)
21
22def __setitem__(self,key,data):
23    self.put(key,data)

Phiên sau đây cho thấy lớp

def hash(astring, tablesize):
    sum = 0
    for pos in range(len(astring)):
        sum = sum + ord(astring[pos])

    return sum%tablesize
6 đang hoạt động. Đầu tiên chúng tôi sẽ tạo bảng băm và lưu trữ một số mục có khóa số nguyên và giá trị dữ liệu chuỗi.

>>> H=HashTable()
>>> H[54]="cat"
>>> H[26]="dog"
>>> H[93]="lion"
>>> H[17]="tiger"
>>> H[77]="bird"
>>> H[31]="cow"
>>> H[44]="goat"
>>> H[55]="pig"
>>> H[20]="chicken"
>>> H.slots
[77, 44, 55, 20, 26, 93, 17, None, None, 31, 54]
>>> H.data
['bird', 'goat', 'pig', 'chicken', 'dog', 'lion',
       'tiger', None, None, 'cow', 'cat']

Tiếp theo chúng tôi sẽ truy cập và sửa đổi một số mục trong bảng băm. Lưu ý rằng giá trị cho khóa 20 đang được thay thế.

>>> H[20]
'chicken'
>>> H[17]
'tiger'
>>> H[20]='duck'
>>> H[20]
'duck'
>>> H.data
['bird', 'goat', 'pig', 'duck', 'dog', 'lion',
       'tiger', None, None, 'cow', 'cat']
>> print(H[99])
None

Ví dụ bảng băm hoàn chỉnh có thể được tìm thấy trong ActiveCode 1.

6.5.4. Phân tích bămAnalysis of Hashing¶

Chúng tôi đã tuyên bố trước đó rằng trong trường hợp tốt nhất sẽ cung cấp một kỹ thuật tìm kiếm thời gian không đổi. Tuy nhiên, do va chạm, số lượng so sánh thường không đơn giản. Mặc dù một phân tích đầy đủ về băm nằm ngoài phạm vi của văn bản này, chúng tôi có thể nêu một số kết quả nổi tiếng gần đúng số lượng so sánh cần thiết để tìm kiếm một mục.\(O(1)\), constant time search technique. However, due to collisions, the number of comparisons is typically not so simple. Even though a complete analysis of hashing is beyond the scope of this text, we can state some well-known results that approximate the number of comparisons necessary to search for an item.

Phần thông tin quan trọng nhất chúng ta cần để phân tích việc sử dụng bảng băm là hệ số tải, \ (\ lambda \). Về mặt khái niệm, nếu \ (\ lambda \) nhỏ, thì có khả năng va chạm thấp hơn, có nghĩa là các mặt hàng có nhiều khả năng nằm trong các khe nơi chúng thuộc về. Nếu \ (\ lambda \) lớn, có nghĩa là bảng đang lấp đầy, thì ngày càng có nhiều va chạm. Điều này có nghĩa là độ phân giải va chạm khó khăn hơn, đòi hỏi nhiều so sánh hơn để tìm một khe trống. Với chuỗi, va chạm tăng lên có nghĩa là tăng số lượng vật phẩm trên mỗi chuỗi.\(\lambda\). Conceptually, if \(\lambda\) is small, then there is a lower chance of collisions, meaning that items are more likely to be in the slots where they belong. If \(\lambda\) is large, meaning that the table is filling up, then there are more and more collisions. This means that collision resolution is more difficult, requiring more comparisons to find an empty slot. With chaining, increased collisions means an increased number of items on each chain.

Như trước đây, chúng tôi sẽ có kết quả cho cả một tìm kiếm thành công và không thành công. Để tìm kiếm thành công bằng cách sử dụng địa chỉ mở với thăm dò tuyến tính, số lượng so sánh trung bình xấp xỉ \ (\ frac {1} {2} \ trái (1+ \ frac {1} {1- \ Lambda} \ Right) và Một tìm kiếm không thành công cho \ (\ frac {1} {2} \ left (1+ \ left (\ frac {1} {1- \ lambda} \ right) Số lượng so sánh trung bình là \ (1 + \ frac {\ lambda} {2} \) cho trường hợp thành công và chỉ đơn giản là \ (\ lambda \) so sánh nếu tìm kiếm không thành công.\(\frac{1}{2}\left(1+\frac{1}{1-\lambda}\right)\) and an unsuccessful search gives \(\frac{1}{2}\left(1+\left(\frac{1}{1-\lambda}\right)^2\right)\) If we are using chaining, the average number of comparisons is \(1 + \frac {\lambda}{2}\) for the successful case, and simply \(\lambda\) comparisons if the search is unsuccessful.

Bạn đã thử các hoạt động trên trang này of activities on this page

Làm thế nào để Python xử lý va chạm băm?

Python Dict sử dụng địa chỉ mở để giải quyết các va chạm băm (xem dictObject. C: 296-297). Trong địa chỉ mở, các va chạm băm được giải quyết bằng cách thăm dò (giải thích bên dưới). Bảng băm chỉ là một khối bộ nhớ tiếp giáp (như một mảng, do đó bạn có thể thực hiện tra cứu O (1) theo chỉ mục).open addressing to resolve hash collisions (see dictobject. c:296-297). In open addressing, hash collisions are resolved by probing (explained below) . The hash table is just a contiguous block of memory (like an array, so you can do O(1) lookup by index).

Làm thế nào để bạn ngăn chặn va chạm băm trong Python?

Trong khi băm, hàm băm có thể dẫn đến một vụ va chạm là hai hoặc nhiều phím được ánh xạ tới cùng một giá trị.Chuỗi băm tránh va chạm.Ý tưởng là làm cho mỗi ô của bảng băm chỉ vào một danh sách các bản ghi được liên kết có cùng giá trị hàm băm.Chain hashing avoids collision. The idea is to make each cell of hash table point to a linked list of records that have same hash function value.

Những cách để giải quyết va chạm trong bảng băm là gì?

Va chạm băm được giải quyết bằng cách mở địa chỉ với thăm dò tuyến tính.Vì Codemonk và băm được băm vào cùng một chỉ số, tức là 2, cửa hàng băm ở mức 3 vì khoảng thời gian giữa các đầu dò liên tiếp là 1. Không có quá 20 phần tử trong tập dữ liệu.Chức năng băm sẽ trả về một số nguyên từ 0 đến 19.open addressing with linear probing. Since CodeMonk and Hashing are hashed to the same index i.e. 2, store Hashing at 3 as the interval between successive probes is 1. There are no more than 20 elements in the data set. Hash function will return an integer from 0 to 19.

Va chạm băm trong Hashtable là gì và nó được xử lý như thế nào?

Trong khoa học máy tính, va chạm băm hoặc đụng độ là khi hai phần dữ liệu trong bảng băm chia sẻ cùng giá trị băm.Giá trị băm trong trường hợp này được lấy từ hàm băm lấy đầu vào dữ liệu và trả về độ dài cố định của các bit.when two pieces of data in a hash table share the same hash value. The hash value in this case is derived from a hash function which takes a data input and returns a fixed length of bits.