hash表 C++的使用以及理解

hash表 C++的使用以及理解

最近在复习和刷leetcode的时候又复习了一遍哈希表,以及在C++中是如何使用的,并且会把做过的题整理到这篇文章中

一、定义哈希表

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

为什么使用哈希表,它带给我们的好处就是可以为寻址带来遍历。由于哈希表的键和值是对应的,查找起来会比较迅速。但是相对的,插入和删除的效率会变低。

比如1、2、3、4、5、6、7、8、9、10 这十个数字,通过对3取余的方式获得下标,当我们想知道某个数字存储位置的时候,只需要用数字除以3,就可以获得下标。

hash表是通过映射的方式,将键值计算出下标。如果映射函数会存在多个键值映射成相同的值的时候,可以采取例如向两边存放等方式,充分利用申请的空间。

具体的方法有:
1、直接定址法:取关键字key的某个线性函数为散列地址,如Hash(key) = key 或 Hash(key) = A*key+B;A,B为常数

2、除留取余法:关键值除以比散列表长度小的素数所得的余数作为散列地址。Hash(key) = key % p;

3、平均取中法:先计算构成关键码的标识符的内码的平方,然后按照散列表的大小取中间的若干位作为散列地址。

4、折叠法:把关键码自左到右分为位数相等的几部分,每一部分的位数应与散列表地址位数相同,只有最后一部分的位数可以短一些。把这些部分的数据叠加起来,就可以得到具有关键码的记录的散列地址。分为移位法和分界法。

5、随机数法:选择一个随机函数,取关键字的随机函数作为它的哈希地址。

6、数学分析法:设有N个d位数,每一位可能有r种不同的符号。这r种不同的符号在各位上出现的频率不一定相同,可能在某些位上分布均匀些,每种符号出现的机会均等;在某些位上分布不均匀,只有某几种符号经常出现。可根据散列表的大小,选取其中各种符号分布均匀的若干位作为散列地址。

二、STL中的hash表

STL模板中存储值和取值的过程如下:

1.得到key
2.通过hash函数得到hash值
3.得到桶号(一般都为hash值对桶数求模)
4.存放key和value在桶内。
其取值过程是:
1.得到key
2.通过hash函数得到hash值
3.得到桶号(一般都为hash值对桶数求模)
4.比较桶的内部元素是否与key相等,若都不相等,则没有找到。
5.取出相等的记录的value。

之前提到了hash表可能多个key值映射为相同的下标,称为哈希冲突,当发生这种情况便需要花费多余的资源去寻找可以存储的下标。

有一个空间换时间的概念,我们在创建hash表的时候要提前知道数据的规模,如果表创建的很大,那么时间上很快,但是浪费空间;如果空间小,造成的冲突次数多,那么会造成查询效率低下

在STL模板中,是为了申请的空间的每一个下标建了一个桶,当多个键值映射为相同的下标,就会把所有的键值在桶中存储起来。当我们通过映射找到桶的编号的时候,去桶中查找是否有自己的键值。

map、hash_map、unorderedmap的区别

map的内部并不是哈希表,而是通过红黑树来实现的。

hash_map内部是我所介绍的哈希表。

这两者的区别是实现的方式不一样,map是一个二叉树,它的存储空间要比hash_map小上很多,并且数据是排号序的,map消耗的空间非常多,但是查找起来十分迅速。我一开始做的时候将map当成了哈希表,他们两个在使用的时候,不计较空间时间,用途我感觉有些类似

unordered_map看其它博客的说法是unordered被录入C++11标准库了,用法和hash_map差不多。

unordered_map基本用法

添加头文件

#include<unordered_map>

创建hash表,两个类型分别为键和值的类型

unordered_map<type, type>table_name;

插入数据

table_name[key] = value

使用迭代器

hash_map<type,type>::iterator iter;
for(  iter = table_name.begin();iter!=table_name.end();iter++){
	cout << iter->first << iter->second;
	table_name.erase(iter)//删除该键值
}

三、哈希表例题

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

你可以按任意顺序返回答案。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归力扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int length = nums.size();
        cout << length;
        vector<int> result;
        map<int, int> hash_int;
        for(int i = 0; i < length; i++){
            hash_int[nums[i]] = i;
        }
        for(int j = 0; j < length; j++){
            if(hash_int.count(target - nums[j])>0){
                int another = hash_int[target-nums[j]];
                cout << another;
                if(j==another){
                    continue;
                }
                result = {j, another};
                break;
            }
        }
        return result;
    }
};

总结

哈希表在题型中,当需要记录每个值的下标,并进行结果输出的时候,会需要用到

这是我第一次写博客,有不足或者补充的地方后期会进行改进,感谢观看!

  • 23
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值