基于数组实现哈希表

哈希表

哈希表又称为散列表,他是建立key与value之间的映射,实现高速的元素查询,简而言之,我们输入一个key,可以快速的查到一个value,时间复杂度为O(1)

例如,每个学生都有学号和姓名,我们可以根据学号快速的知道姓名。

元素查询效率的对比

数组链表哈希表
查找元素O(1)O(n)O(1)
添加元素O(1)O(1)O(1)
删除元素O(n)O(n)O(1)

哈希表的常用操作

哈希表的常用操作包括:初始化哈希表,查询操作,添加键值对,删除键值对等

//
// Created by Administrator on 2024/1/11.
//
#include "iostream"
#include "unordered_map"
#include "string"

using namespace std;

int main(){
    //初始化哈希表
    unordered_map<int,string > map;
    //添加操作
    map[123]="张三";
    map[456]="李四";
    map[789]="王五";
    //查询操作
    string name = map[123];
    cout<<name<<endl;
    //删除操作
    map.erase(123);
    return 0;
}
  • 哈希表的遍历有三种方式:遍历键值对,遍历键,遍历值
//
// Created by Administrator on 2024/1/11.
//
#include "iostream"
#include "unordered_map"
#include "string"

using namespace std;

int main(){
    //初始化哈希表
    unordered_map<int,string > map;
    //添加操作
    map[123]="张三";
    map[456]="李四";
    map[789]="王五";
    //遍历键值对
    cout<<"遍历键值对"<<endl;
    for(auto kv:map){
        cout<<kv.first<<"->"<<kv.second<<endl;
    }
    cout<<"----------------------"<<endl;
    cout<<"使用迭代器遍历"<<endl;
    for(auto iter = map.begin();iter != map.end();iter++){
        cout<<iter->first<<"->"<<iter->second<<endl;
    }
    return 0;
}
//输出结果
遍历键值对
789->王五
456->李四
123->张三
----------------------
使用迭代器遍历
789->王五
456->李四
123->张三

哈希表的简单实现

哈希函数:将一个较大的输入空间映射到一个较小的输出空间。

输入一个key,我们可以通过哈希函数得到该key对应的键值对在数组中的存储位置。

哈希函数的计算步骤:

1.通过某种哈希算法hash()计算得到哈希值

2.将hash()值与数组容量取模,从而得到该key值对应的数组索引index

index = hash(key) % capacity

基于数组的实现

设数组长度 capacity = 100;

哈希算法hash(key) = key;

哈希函数 key % 100

//
// Created by Administrator on 2024/1/11.
//
#include "iostream"
#include "string"
#include "vector"

using namespace std;

struct Pair{
    int key;
    string val;
    Pair(int key,string val){
        this->key = key;
        this->val = val;
    }
};
class arrayHash{
private:
    vector<Pair *> buckets;
public:
    arrayHash(){
        buckets = vector<Pair*>(100);
    }
    int hashFuction(int key){
        return key % 100;
    }
    //查询操作
    string get(int key){
        int index = hashFuction(key);
        Pair* temp = buckets[index];
        if(temp == nullptr){
            return "";
        }
        return temp->val;
    }
    //添加操作
    void put(int key,string val){
        int index = hashFuction(key);
        Pair *temp = new Pair(key,val);
        buckets[index] = temp;
    }
    //删除操作
    void remove(int key){
        int index = hashFuction(key);
        delete buckets[index];
        buckets[index] = nullptr;
    }
    /* 获取所有键值对 */
    vector<Pair *> pairSet() {
        vector<Pair *> pairSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                pairSet.push_back(pair);
            }
        }
        return pairSet;
    }
    /* 获取所有键 */
    vector<int> keySet() {
        vector<int> keySet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                keySet.push_back(pair->key);
            }
        }
        return keySet;
    }
    /* 获取所有值 */
    vector<string> valueSet() {
        vector<string> valueSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                valueSet.push_back(pair->val);
            }
        }
        return valueSet;
    }
    /* 打印哈希表 */
    void print() {
        for (Pair *kv : pairSet()) {
            cout << kv->key << " -> " << kv->val << endl;
        }
    }
};

int main(){
    cout<<"测试基于数组实现的哈希表"<<endl;
    arrayHash hash;
    cout<<"添加三组数据"<<endl;
    hash.put(123,"张三");
    hash.put(456,"李四");
    hash.put(789,"王五");
    cout<<"打印输出哈希表"<<endl;
    hash.print();
    cout<<"查询456的信息:"<<hash.get(456)<<endl;
    cout<<"删除123的信息:"<<endl;
    hash.remove(123);
    cout<<"打印输出哈希表"<<endl;
    hash.print();
    cout<<"获取所有的键值对"<<endl;
    vector<Pair*> temp = hash.pairSet();
    for(Pair * i : temp){
        cout<<i->key<<"->"<<i->val<<endl;
    }
    cout<<"获取所有的键:"<<endl;
    vector<int> key = hash.keySet();
    for(auto i : key){
        cout<<i<<endl;
    }
    cout<<"获取所有的值"<<endl;
    vector<string> val = hash.valueSet();
    for(auto i : val){
        cout<<i<<endl;
    }
    return 0;

}
//输出结果
测试基于数组实现的哈希表
添加三组数据
打印输出哈希表
123 -> 张三
456 -> 李四
789 -> 王五
查询456的信息:李四
删除123的信息:
打印输出哈希表
456 -> 李四
789 -> 王五
获取所有的键值对
456->李四
789->王五
获取所有的键:
456
789
获取所有的值
李四
王五

哈希冲突与扩容

从本质上看,哈希函数的作用是将所有输入的key映射到数组所有构成的索引空间,然而,输入空间往往大于输出空间,因此,理论上存在”多个输入对应一个输出“

  • 对于上述的哈希函数,当输入的key的后两位相同时,哈希函数输出的结果也是相同的,例如学号为12934和13034

    得到

    12934 % 100 = 34

    13034 % 100 = 34

  • 两个学号指向了同一个索引,这显然是不对的,当多个输入对应一个输出时,我我们称之为哈希冲突。

  • 可以想到,当哈希表的容量越大,多个key被映射到同一个索引的概率就会降低,冲突就会减少,因此,我们可以通过扩容哈希表来减少哈希冲突。

  • 负载因子:哈希表元素的数量除以哈希表的容量,用于衡量哈希冲突的严重程度,也常常作为哈希扩容的出发条件。

关注微信公众号:IT零壹学府,每日分享自己的学习经验。

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零壹寻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值