哈希表的简单构造以及拉链式解决冲突
哈希表
用来存储特定形式的元素,存储到不同的键值中,例如在一个数组中{1,2,3,3,4},我们要统计各个元素的数量,可以创建一个数组a[5],a[0]代表0的个数a[1]代表1的个数…,数组的大小取决于数组中最大值和最小值,如果最大值非常大,就没办这样创建哈希表,于是我们可以创建一个小的哈希表,那要怎么表示大的数据呢,可以对大的数据与哈希表的长度进行取余,但是这时可能会有元素之间的冲突,两个元素占据同一个位置,所以就有了拉链式解决冲突
拉链式解决冲突
这里哈希表的每个节点都定义为单链表,然后如果出现冲突元素,就把该元素存到链表头的位置
代码部分
1.单链表定义
成员需要有一个自身的值,代表该元素的值,还需要一个指针,指向下一个节点
struct ListNode //单链表
{
int val;
ListNode *next;
ListNode(int x):val(x),next(NULL) {
};
};
2.寻找元素的键值
直接用当前元素与哈希表的长度取余
int hash_func(int key,int table_len) //返回当前元素应该在的位置
{
return key%table_len;
}
3.头插法向哈希表中插入元素
每次插入都插入该链表中头的位置,然后更新头节点
//头插法
void insert(ListNode *hash_table[],ListNode *node,int table_len)
{
int hash_key=hash_func(node->val,table_len);
node->next=hash_table[hash_key];
hash_table[hash_key]=node;
}
4.查找元素
首先找到元素的键值,然后对应的单链表中查询,查询到返回true,到最后没有查询到返回false
//查找
bool search(ListNode *hash_table[],int value,int table_len)
{
int hash_key=hash_func(value,table_len);
ListNode *head=hash_table[hash_key];
while(head)
{
if(head->val==value)
return true;
head=head->next;
}
return false;
5.主函数部分(用来测试)
创建一个vector<ListNode *>类型的变量用来将所有数组中的整型进行类型的转换(转换成ListNode *类型),然后利用写好的insert函数将所有元素插入到哈希表中,然后打印哈希表中的所有元素。
测试查找函数功能,在哈希表中查找0~9
int main (void)
{
const int table_len=11;
ListNode *hash_table[table_len]={
0};
vector<ListNode *> hash_node_vec;
int test[8]={
1,1,4,9,20,30,150,500};
for(int i=0;i<8;i++)
hash_node_vec.push_back(new ListNode(test[i]));
for(int i=0;i<hash_node_vec.size();i++)
{
insert(hash_table,hash_node_vec[i],table_len);
}
//打印哈希表
cout<<"Hash table\n";
for(int i=0;i<table_len;i++)
{
printf("[%d]",i);
ListNode *head=hash_table[i];
while(head)
{
printf("->%d",head->val);
head=head->next;
}
cout<<endl;
}
cout<<endl;
cout<<"Test search(0~9)\n";
for(int i=0;i<10;i++)
{
if(search(hash_table,i,table_len))
{
cout<<i<<" is in the hash table.\n";
}
else
{
cout<<i<<" is not in the hash table.\n";
}
}
return 0;
}
总结
在很多算法题中,哈希表的使用频率很高,而且可以利用哈希表存储数据避免重复运算,达到空间换时间的目的