基于数组实现哈希表

哈希表

哈希表又称为散列表,他是建立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 map;
    //添加操作
    map[123]="张三";
    map[456]="李四";
    map[789]="王五";
    //查询操作
    string name = map[123];
    cout<
  • 哈希表的遍历有三种方式:遍历键值对,遍历键,遍历值
//
// Created by Administrator on 2024/1/11.
//
#include "iostream"
#include "unordered_map"
#include "string"

using namespace std;

int main(){
    //初始化哈希表
    unordered_map map;
    //添加操作
    map[123]="张三";
    map[456]="李四";
    map[789]="王五";
    //遍历键值对
    cout<<"遍历键值对"<"<first<<"->"<second<王五
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 buckets;
public:
    arrayHash(){
        buckets = vector(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 pairSet() {
        vector pairSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                pairSet.push_back(pair);
            }
        }
        return pairSet;
    }
    /* 获取所有键 */
    vector keySet() {
        vector keySet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                keySet.push_back(pair->key);
            }
        }
        return keySet;
    }
    /* 获取所有值 */
    vector valueSet() {
        vector 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<<"测试基于数组实现的哈希表"< temp = hash.pairSet();
    for(Pair * i : temp){
        cout<key<<"->"<val< key = hash.keySet();
    for(auto i : key){
        cout< val = hash.valueSet();
    for(auto i : val){
        cout< 张三
456 -> 李四
789 -> 王五
查询456的信息:李四
删除123的信息:
打印输出哈希表
456 -> 李四
789 -> 王五
获取所有的键值对
456->李四
789->王五
获取所有的键:
456
789
获取所有的值
李四
王五

哈希冲突与扩容

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

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

    得到

    12934 % 100 = 34

    13034 % 100 = 34

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

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

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

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

你可能感兴趣的:(数据结构,数据结构)