【链表】day4 【链表】day3
目录
前言
一、三种哈希结构
数组
散列技术(哈希思想)
哈希碰撞
set(集合)
map(映射)
二、哈希表的一些应用
总结
哈希表(也叫散列表)是一种较为常用的数据结构,我们常用的数组其实就是一种简单的哈希表。而本文将介绍哈希思想,哈希法实现的三种哈希结构以及哈希表的一些应用。
在我们使用哈希表时,通常需要从信息中提取出“key”和"value"这两个信息。
比如上图,如果我们要查询学生的中文名字时,可以将学号作为所谓的“key”,然后将学号下对应的中文名字视作"value",通过“key”查找“value”所形成的这么一组信息被称为键值对。当然,作为"key"的不一定是数字,我们也可以将学生的英文名字作为“key”。key的取值不定,往往根据查找信息而确立。
那么我们确立好键值对后该怎么对数据进行储存呢?我们一般会使用如下三种数据结构:
·数组 ·set(集合) ·map(映射)
我们可以将数组的角标作为key,然后中文名字作为数组的值,这样我们可以通过数组角标查值,完成以键查值的操作。但问题是,我们的数组角标都是1,2,3......这样较小的数字,如果使用1021这样,甚至更大的数字作为角标,毫无疑问会造成内存浪费。如果我们使用学生的英文名字作为“key”,甚至都不能作为数组角标。那么我们应该如何解决这个问题呢?
当我们的key值为一些较大的或者不太规律的数字时,我们可以通过对数字进行适当运算来,来将其转化为可适用的角标。以1021为例,我们可以将其减去1020以获得适当的角标。而当我们的key值为一些字母时,可以计算其与首字母的位置。这样的方法也被称为散列技术。
例1
class Solution
{
public:
int numJewelsInStones(string jewels, string stones)
{
int hash1[26];
int hash2[26];
int sum = 0;
for (int i = 0; i < jewels.length(); i++)
{
if (jewels[i] >= 'A' && jewels[i] <= 'Z')
{
hash1[jewels[i] - 'A']++;
}
else
{
hash2[jewels[i] - 'a']++;
}
}
for (int i = 0; i < stones.length(); i++)
{
if (stones[i] >= 'A' && stones[i]<= 'Z')
{
if (hash1[stones[i] - 'A'] != 0)
{
sum++;
}
}
else
{
if (hash2[stones[i] - 'a'] != 0)
{
sum++;
}
}
}
return sum;
}
};
该例题就利用了散列技术,将字母转化为合适的key值,并利用该key值进行查找。
如果张三和李四都喜欢“john"这个名字,那么如果将英文名字作为key值,就会造成key值重复,这就是所谓的哈希碰撞。
那么我们如何解决这样的"这样的碰撞”呢?以下有两种解决方案。
·拉链法
直接将冲突元素作为链表节点连接冲突角标后。
·线性探测法
将冲突元素放置下一个空位,这种方法一定要保证tableSize要大于dataSize。
这两种数据结构属于STL库中的内容,我们只需要掌握其使用方法即可,不需要深究其内部实现。
例2
bool isAnagramMap(string s, string t)
{
unordered_map map;
if (s.length() != t.length())
return false;
for (int i = 0; i < s.length(); i++)
{
auto iter = map.find(s[i]);
if (iter != map.end())
iter->second++;
map.insert(pair(s[i],1));
}
for (int j = 0; j < t.length(); j++)
{
auto iter = map.find(t[j]);
if (iter != map.end() && iter->second > 0)
iter->second--;
else
return false;
}
return true;
}
bool isAnagramArray(char* s, char* t)
{
int i, x[26] = { 0 }, y[26] = { 0 };
for (i = 0; s[i] != '\0'; i++) x[s[i] - 'a']++;
for (i = 0; t[i] != '\0'; i++) y[t[i] - 'a']++;
for (i = 0; i < 26; i++)
if (x[i] != y[i]) return false;
return true;
}
例3
vector twoSum(vector& nums, int target)
{
unordered_mapmap1,map2;
for (int i = 0; i < nums.size(); i++)
{
auto iter = map2.find(nums[i]);
if (iter != map2.end())
iter->second++;
map1.insert(pair(nums[i], i));
map2.insert(pair(nums[i], 1));
}
for (int i = 0; i < nums.size(); i++)
{
auto iter1 = map1.find(target - nums[i]);
auto iter2 = map2.find(target - nums[i]);
if (iter1 != map1.end())
{
if (i == iter1->second || (iter2->second == 1 &&
nums[i] == iter1->first))
continue;
return { i,iter1->second };
}
}
return {};
}
例4
以上就是今天要讲的内容,本文仅仅简单介绍了哈希表的使用,而使用好哈希结构和哈希思想对于于解决和优化一些问题有重要作用。