哈希表(C/C++)

特点:

哈希表也称散列表,即在记录的存储地址(散列地址)和它的关键码(散列表)之间建立一个确定的对应关系(散列函数),如此,不经过比较,一次读取就能得到所查元素的查找方法。

散列表一般不适用于多个记录有同样关键码的情况;也不适用于范围的查找,如不能找到最大值或最小值。

散列函数的常用设计方法:

1、直接定址法:散列函数是关键码的线性函数,即 H(key)=a*key+b
适用于:事先知道关键码,关键码集合不大且连续性较好。
2、除留余数法:确定一个合适的整数p,H(key)=key mod p (mod:取余)
如何减少冲突:在确定了关键码个数后,哈希表的长度n一般选取比关键码数量略大的质数。
3、数字分析法:根据关键码在各个位上的分布情况,选取分布比较均匀的若干位组成散列地址。
适用情形:如存储学号,一般学号的前缀虽相同,但后两位肯定不同,可根据后两位来确定存储地址。
4、平方取中法:对关键码平方后,按散列表大小,取中间的若干位作为散列地址
适用于:事先不知道关键码且关键码位数不大
5、折叠法:将关键码从左到右分割成位数相等的几部分,将这几部分叠加求和,取结果的后几位作为存储地址
适用于:关键码位数较多,且事先不知道关键码的分别情况
散列函数并不局限于以上方法,可以根据实际需要自己设计。

当散列地址产生了冲突,如何处理:

1、开放定址法——线性探测法:发生冲突时,就去寻找下一个空的散列地址并将数据存入。
对于关键值key,散列表长度为m,则寻找下一个散列地址的公式为:
H=(H(key)+d)%m(d=1,2,3,…,m-1)
这种处理方法称为闭散列表
2、拉链法(链地址法):存放数据的结构体内部定义一个头指针,将产生冲突的关键码存放在头指针所指的链表中。
如此便可将同一类型的数据都集中在同一个结构体中,而不会像上一个方法那样产生堆积(抢占其他关键码的位置)。
当链表的结点大于8时,可将其转换为红黑树,提高搜索效率。

具体实现:

以下采用除留余数法和拉链法实现哈希表:

//哈希表
typedef struct HashLink
{
    int key=0;
    HashLink *next=nullptr;
}HashLink;
typedef struct HashMap
{
    int key=0;
    bool flag=false;//表示key是否已经存储了数据
    HashLink *head=nullptr;
}HashMap;

//哈希碰撞:拉链法
//在链表中插入元素val,当个数大于8时转换为红黑树(这里暂不实现此功能)
void CreatLink(vector<HashMap> &H,int val)
{
    if(H[val%7].head==nullptr)
    {
        H[val%7].head=new HashLink;
        H[val%7].head->key=val;
    }
    else
    {
        HashLink *p=H[val%7].head;
        while(p->next!=nullptr)
        {
            p=p->next;
        }
        p->next=new HashLink;
        p->next->key=val;
    }
}

//创建哈希表
void CreatHashMap(vector<HashMap> &H)
{
    //确定数据
    vector<int> v;
    cout << "请输入要存储的数据(结束输入:100011):" << endl;
    int val=0;
    cin >> val;
    while(val!=END)
    {
        v.push_back(val);
        cin >> val;
    }
    //创建哈希表
    int n=v.size();
    H.resize(n);
    for(int i=0;i<n;++i)
    {
        if(H[v[i]%7].flag==false)
        {
            H[v[i]%7].key=v[i];
            H[v[i]%7].flag=true;
        }
        else
        {
            CreatLink(H,v[i]);
        }
    }
}

//哈希函数:除留余数法
bool SearchHashMap(vector<HashMap> &H,int val)
{
    if(H[val%7].key==val)
        return true;
    else
    {
        auto p=H[val%7].head;
        while(p!=nullptr)
        {
            if(p->key==val)
                return true;
            else
                p=p->next;
        }
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值