哈希表数据结构以键值对的形式存储元素,其中
- 键 - 用于索引值的唯一整数
- 值 - 与键关联的数据。

哈希(哈希函数)
在哈希表中,使用键处理新索引。然后,将与该键对应的元素存储在该索引中。这个过程称为哈希。
设k为键,h(x)为哈希函数。
这里,h(k)将为我们提供一个新索引来存储与k关联的元素。

要了解更多信息,请访问哈希。
哈希冲突
当哈希函数为多个键生成相同的索引时,将发生冲突(在该索引中存储什么值)。这称为哈希冲突。
我们可以使用以下一种技术来解决哈希冲突。
- 通过链表解决冲突
- 开放寻址:线性/二次探测和双重哈希
1. 通过链表解决冲突
在链表中,如果哈希函数为多个元素生成相同的索引,则这些元素通过使用双向链表存储在同一索引中。
如果j
是多个元素的槽,它包含指向元素列表头部的指针。如果没有元素,j
包含NIL
。

操作的伪代码
chainedHashSearch(T, k)
return T[h(k)]
chainedHashInsert(T, x)
T[h(x.key)] = x //insert at the head
chainedHashDelete(T, x)
T[h(x.key)] = NIL
2. 开放寻址
与链表不同,开放寻址不将多个元素存储在同一槽中。在这里,每个槽要么填充有单个键,要么留空NIL
。
开放寻址中使用的不同技术有
i. 线性探测
在线性探测中,通过检查下一个槽来解决冲突。
h(k, i) = (h′(k) + i) mod m
其中
i = {0, 1, ….}
h'(k)
是一个新的哈希函数
如果h(k, 0)
处发生冲突,则检查h(k, 1)
。这样,i
的值会线性增加。
线性探测的问题在于,一串相邻的槽会被填满。在插入新元素时,必须遍历整个簇。这会增加执行哈希表操作所需的时间。
ii. 二次探测
它的工作原理与线性探测类似,但通过使用以下关系,槽之间的间隔会增加(大于一)。
h(k, i) = (h′(k) + c1i + c2i2) mod m
其中,
c1
和c2
是正辅助常数,i = {0, 1, ….}
iii. 双重哈希
如果应用哈希函数h(k)
后发生冲突,则会计算另一个哈希函数来查找下一个槽。
h(k, i) = (h1(k) + ih2(k)) mod m
好的哈希函数
好的哈希函数可能无法完全避免冲突,但可以减少冲突的数量。
在这里,我们将介绍查找好哈希函数的不同方法
1. 除法法
如果k
是键,m
是哈希表的大小,则哈希函数h()
计算为
h(k) = k mod m
例如,如果哈希表的大小是10
,k = 112
,则h(k) = 112
mod 10 = 2
。m
的值不能是2
的幂。这是因为2
的幂的二进制格式是10, 100, 1000, …
。当我们找到k mod m
时,我们将始终得到低阶p位。
if m = 22, k = 17, then h(k) = 17 mod 22 = 10001 mod 100 = 01 if m = 23, k = 17, then h(k) = 17 mod 22 = 10001 mod 100 = 001 if m = 24, k = 17, then h(k) = 17 mod 22 = 10001 mod 100 = 0001 if m = 2p, then h(k) = p lower bits of m
2. 乘法法
h(k) = ⌊m(kA mod 1)⌋
其中,
kA mod 1
给出小数部分kA
,⌊ ⌋
给出下限值A
是任何常数。A
的值介于0和1之间。但是,Knuth建议的最佳选择是≈ (√5-1)/2
。
3. 散列
在散列中,哈希函数是根据与键无关的方式随机选择的。
Python、Java 和 C/C++ 示例
# Python program to demonstrate working of HashTable
# Initialize the hash table with 10 empty lists (each index is a list to handle collisions)
hashTable = [[] for _ in range(10)]
def checkPrime(n):
if n == 1 or n == 0:
return 0
for i in range(2, n // 2):
if n % i == 0:
return 0
return 1
def getPrime(n):
if n % 2 == 0:
n = n + 1
while not checkPrime(n):
n += 2
return n
def hashFunction(key):
capacity = getPrime(10)
return key % capacity
def insertData(key, data):
index = hashFunction(key)
# Check if the key already exists in the list to update it, otherwise append
found = False
for i, kv in enumerate(hashTable[index]):
if kv[0] == key:
hashTable[index][i] = (key, data) # Update existing key-value pair
found = True
break
if not found:
hashTable[index].append((key, data)) # Add new key-value pair if not found
def removeData(key):
index = hashFunction(key)
# Remove the key-value pair from the list if it exists
for i, kv in enumerate(hashTable[index]):
if kv[0] == key:
del hashTable[index][i]
break
# Test the hash table
insertData(123, "apple")
insertData(432, "mango")
insertData(213, "banana")
insertData(654, "guava")
insertData(213, "orange") # This should update the value for key 213
print(hashTable)
removeData(123)
print(hashTable)
// Java program to demonstrate working of HashTable
import java.util.*;
class HashTable {
public static void main(String args[])
{
Hashtable<Integer, Integer>
ht = new Hashtable<Integer, Integer>();
ht.put(123, 432);
ht.put(12, 2345);
ht.put(15, 5643);
ht.put(3, 321);
ht.remove(12);
System.out.println(ht);
}
}
// Implementing hash table in C
#include <stdio.h>
#include <stdlib.h>
struct set
{
int key;
int data;
};
struct set *array;
int capacity = 10;
int size = 0;
int hashFunction(int key)
{
return (key % capacity);
}
int checkPrime(int n)
{
int i;
if (n == 1 || n == 0)
{
return 0;
}
for (i = 2; i < n / 2; i++)
{
if (n % i == 0)
{
return 0;
}
}
return 1;
}
int getPrime(int n)
{
if (n % 2 == 0)
{
n++;
}
while (!checkPrime(n))
{
n += 2;
}
return n;
}
void init_array()
{
capacity = getPrime(capacity);
array = (struct set *)malloc(capacity * sizeof(struct set));
for (int i = 0; i < capacity; i++)
{
array[i].key = 0;
array[i].data = 0;
}
}
void insert(int key, int data)
{
int index = hashFunction(key);
if (array[index].data == 0)
{
array[index].key = key;
array[index].data = data;
size++;
printf("\n Key (%d) has been inserted \n", key);
}
else if (array[index].key == key)
{
array[index].data = data;
}
else
{
printf("\n Collision occured \n");
}
}
void remove_element(int key)
{
int index = hashFunction(key);
if (array[index].data == 0)
{
printf("\n This key does not exist \n");
}
else
{
array[index].key = 0;
array[index].data = 0;
size--;
printf("\n Key (%d) has been removed \n", key);
}
}
void display()
{
int i;
for (i = 0; i < capacity; i++)
{
if (array[i].data == 0)
{
printf("\n array[%d]: / ", i);
}
else
{
printf("\n key: %d array[%d]: %d \t", array[i].key, i, array[i].data);
}
}
}
int size_of_hashtable()
{
return size;
}
int main()
{
int choice, key, data, n;
int c = 0;
init_array();
do
{
printf("1.Insert item in the Hash Table"
"\n2.Remove item from the Hash Table"
"\n3.Check the size of Hash Table"
"\n4.Display a Hash Table"
"\n\n Please enter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("Enter key -:\t");
scanf("%d", &key);
printf("Enter data -:\t");
scanf("%d", &data);
insert(key, data);
break;
case 2:
printf("Enter the key to delete-:");
scanf("%d", &key);
remove_element(key);
break;
case 3:
n = size_of_hashtable();
printf("Size of Hash Table is-:%d\n", n);
break;
case 4:
display();
break;
default:
printf("Invalid Input\n");
}
printf("\nDo you want to continue (press 1 for yes): ");
scanf("%d", &c);
} while (c == 1);
}
// Implementing hash table in C++
#include <iostream>
#include <list>
using namespace std;
class HashTable
{
int capacity;
list<int> *table;
public:
HashTable(int V);
void insertItem(int key, int data);
void deleteItem(int key);
int checkPrime(int n)
{
int i;
if (n == 1 || n == 0)
{
return 0;
}
for (i = 2; i < n / 2; i++)
{
if (n % i == 0)
{
return 0;
}
}
return 1;
}
int getPrime(int n)
{
if (n % 2 == 0)
{
n++;
}
while (!checkPrime(n))
{
n += 2;
}
return n;
}
int hashFunction(int key)
{
return (key % capacity);
}
void displayHash();
};
HashTable::HashTable(int c)
{
int size = getPrime(c);
this->capacity = size;
table = new list<int>[capacity];
}
void HashTable::insertItem(int key, int data)
{
int index = hashFunction(key);
table[index].push_back(data);
}
void HashTable::deleteItem(int key)
{
int index = hashFunction(key);
list<int>::iterator i;
for (i = table[index].begin();
i != table[index].end(); i++)
{
if (*i == key)
break;
}
if (i != table[index].end())
table[index].erase(i);
}
void HashTable::displayHash()
{
for (int i = 0; i < capacity; i++)
{
cout << "table[" << i << "]";
for (auto x : table[i])
cout << " --> " << x;
cout << endl;
}
}
int main()
{
int key[] = {231, 321, 212, 321, 433, 262};
int data[] = {123, 432, 523, 43, 423, 111};
int size = sizeof(key) / sizeof(key[0]);
HashTable h(size);
for (int i = 0; i < size; i++)
h.insertItem(key[i], data[i]);
h.deleteItem(12);
h.displayHash();
}
哈希表应用
哈希表实现于
- 需要常数时间查找和插入
- 加密应用
- 需要索引数据