算不上详解 只有散列函数的介绍 还有我用了一整节数据结构再加一个多小时调出来的代码
/*
好的散列函数要求:(1)计算简单,至少散列函数的计算时间不应该超过其他查找技术与关键字
比较的时间;(2)计算出的散列地址分布均匀,这样可以保证存储空间的有效利用,并减少为处理
冲突而耗费的时间。
1. 直接定址法
取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,
其中a和b为常数(这种散列函数叫做自身函数)。
2. 数字分析法
假设某公司的员工登记表以员工的手机号作为关键字。手机号一共11位。
前3位是接入号,对应不同运营商的子品牌;中间4位表示归属地;最后4位是用户号。
不同手机号前7位相同的可能性很大,所以可以选择后4位作为散列地址,或者对后4位反转
(1234 -> 4321)、循环右移(1234 -> 4123)、循环左移等等之后作为散列地址。
数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关
键字的若干位分布比较均匀,就可以考虑这个方法。
3. 平方取中法
假设关键字是1234、平方之后是1522756、再抽取中间3位227,用作散列地址。平
方取中法比较适合于不知道关键字的分布,而位数又不是很大的情况。
4. 折叠法
将关键字从左到右分割成位数相等的几部分,最后一部分位数不够时可以短些,
然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。
比如关键字是9876543210,散列表表长是3位,将其分为四组,然后叠加求和:
987 + 654 + 321 + 0 = 1962,取后3位962作为散列地址。
折叠法事先不需要知道关键字的分布,适合关键字位数较多的情况。
5. 除留余数法
f(key) = key mod p (p≤m),m为散列表长。这种方法不仅可以对关键字直接取模,
也可在折叠、平方取中后再取模。根据经验,若散列表表长为m,通常p为小于或等于表长
(最好接近m)的最小质数,可以更好的减小冲突。
此方法为最常用的构造散列函数方法。
6. 随机数法
f(key) = random(key),这里random是随机函数。当关键字的长度不等时,采用这个方法
构造散列函数是比较合适的。
实际应用中,应该视不同的情况采用不同的散列函数。如果关键字是英文字符、中文字符、
各种各样的符号,都可以转换为某种数字来处理,比如其unicode编码。下面这些因素可以作为
选取散列函数的参考:(1)计算散列地址所需的时间;(2)关键字长度;(3)散列表大小;
(4)关键字的分布情况;(5)查找记录的频率。
*/
#include <iostream>
using namespace std;
const int len = 13;
struct hash_node {
int data;
hash_node *next;
};
int hash(int num){
return num%len;
}
void collision(hash_node *vec[], int elem, hash_node *new1){
if(vec[elem] == NULL){
vec[elem] = new1;
vec[elem]->next = NULL;
}
else{
new1->next = vec[elem];
vec[elem] = new1;
}
}
void create_hash(hash_node *vec[], int num){
int arr[num];
for(int i=0; i<num; i++){
cin >> arr[i];
}
hash_node *p;
int tmp;
for(int i=0; i<num; i++){
p = new hash_node;
p->data = arr[i];
p->next = NULL;
tmp = hash(arr[i]);
collision(vec, tmp, p);
}
}
void print_hash(hash_node *vec[]){
hash_node *tmp;
for(int i=0; i<len; i++){
cout << i+1 << ": ";
tmp = vec[i];
if(tmp == NULL)
cout << "NULL";
else{
while(tmp){
cout << tmp->data << ' ';
tmp = tmp->next;
}
}
cout << endl;
}
}
void insert_hash_node(hash_node *vec[], int num){
hash_node *p;
p = new hash_node;
p->data = num;
p->next = NULL;
int tmp = hash(num);
collision(vec, tmp, p);
}
void delete_hash_node(hash_node *vec[], int num){
hash_node *p, *tmp;
/*int flag = 1;
for(int i=0; i<len; i++){ ///这里我想的是遍历节点数组,然后再一个链表一个链表的找
cout << i << endl; ///但是这样做是不对的,因为没存链表的节点我压根就没有置空
tmp = vec[i]; ///然后就悲剧地死循环了 呵呵哒 调了半天才出来(测试的语句请无视)
cout << "1" << endl;///而且这个方法真是越想越麻烦 这个需要遍历 而下面的方法
if(tmp && tmp->data == num){ ///只需走一个链表
p = tmp->next;
delete tmp;
tmp = p;
}
cout << "2" << endl;
while(tmp){
if(tmp->data == num){
p->next = tmp->next;
flag = 0;
delete tmp;
}
p = tmp;
tmp = tmp->next;
}
}
if(flag)
cout << "not founded!" << endl;*/
///没关系 我们还有别的方法~~~
int elem;
elem = hash(num);
if(vec[elem] == NULL){
cerr << "vec[" << elem << "] is NULL" << endl;
}
else{
tmp = vec[elem];
while(tmp->data != num){
if(tmp->next == NULL){
cerr << "not found" << endl;
}
p = tmp;
tmp = tmp->next;
}
p->next = tmp->next;
delete tmp;
}
}
int main()
{
int num = 12;
hash_node *vec[len];
for(int i=0; i<len; i++){
vec[i] = NULL;
}
cout << "************************" << endl;
create_hash(vec, num);
print_hash(vec);
cout << "*************************" << endl;
insert_hash_node(vec, 29);
print_hash(vec);
cout << "*************************" << endl;
delete_hash_node(vec, 1);
print_hash(vec);
return 0;
}
///19 14 23 01 68 20 84 27 55 11 10 79
************************
19 14 23 01 68 20 84 27 55 11 10 79
1: NULL
2: 79 27 1 14
3: NULL
4: 55 68
5: NULL
6: NULL
7: 84 19
8: 20
9: NULL
10: NULL
11: 10 23
12: 11
13: NULL
*************************
1: NULL
2: 79 27 1 14
3: NULL
4: 29 55 68
5: NULL
6: NULL
7: 84 19
8: 20
9: NULL
10: NULL
11: 10 23
12: 11
13: NULL
*************************
1: NULL
2: 79 27 14
3: NULL
4: 29 55 68
5: NULL
6: NULL
7: 84 19
8: 20
9: NULL
10: NULL
11: 10 23
12: 11
13: NULL
Process returned 0 (0x0) execution time : 4.705 s
Press any key to continue.
多测几组数据就会发现上面的删除部分是不完善的, 没有考虑删第一个元素
但是下面的还不够全面 不能同时删除包括第一个元素在内的多个元素, 我再改改
<pre class="cpp" name="code">void delete_hash_node (hash_node *vec[], int num){
hash_node *p, *q;
int elem = hash(num);
p = vec[elem];
if(vec[elem] == NULL){
cout << "not founded\n";
}
else if(vec[elem]->data == num){
q = p->next;
delete p;
vec[elem] = q;
}
else{
int flag = 0;
while(p){
if(p->data == num){
flag = 1;
q->next = p->next;
delete p;
}
q = p;
p = p->next;
}
if(flag == 0){
cout << "not founded!\n";
}
}
}