哈希表

 算不上详解 只有散列函数的介绍 还有我用了一整节数据结构再加一个多小时调出来的代码

/*
好的散列函数要求:(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";
        }
    }
}

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值