学习笔记:枚举与优化之unordered_set/map

Poki的学习笔记:枚举与优化之unordered_set/map

  • 是什么
  • unordered_map与unordered_set区别
  • 与set/map的区别
  • 具体应用

本笔记随时会更改,仅代表个人理解,参考了许多博文资料,也许会有很多错漏希望指正。

是什么

特点:无序

应用:快速查找删除 统计次数问题 无序容器

unordered_set&unordered_map内部实现均基于哈希表(采用除留余数法)
P.S. 哈希表——根据关键码值而进行直接访问的数据结构,通过相应的哈希函数(也称散列函数)处理关键字得到相应的关键码值,关键码值对应着一个特定位置,用该位置来存取相应的信息,这样就能以较快的速度获取关键字的信息。会存在不可避免的冲突问题。解决冲突的方法常见的有:开发地址法、再散列法、链地址法(也称拉链法)。而unordered_set/map内部解决冲突采用的是链地址法,当用冲突发生时把具有同一关键码的数据组成一个链表。[数据结构学了就不多赘述了>_<]

以unordered_set为例,在一个unordered_set内部,元素不会按任何顺序排序,而是通过元素值的hash值将元素分组放置到各个槽(Bucker,也可以译为“桶”),这样就能通过元素值快速访问各个对应的元素(均摊耗时为O(1))
当我只要访问而不需要顺序,想用空间弥补时间时,哈希表是很好的选择。

unordered_map与unordered_set区别

后者就是在哈希表插入value,而这个value就是它自己的key,而unordered_map有键-值对,unordered_set单纯就是为了方便查询这些值。

使用unordered_set的例子:给你A,B两组数,由整数组成,然后把B中在A中出现的数字取出来,要求用线性时间完成。很明显,这道题应该将A的数放到一个表格,然后线性扫描B,发现存在的就取出。可是A的范围太大,你不可能做一个包含所有整数的表,因为这个域太大了,所以我们就用unordered_set来存放A的数,具体实现库函数已经帮你搞定了。

与set/map的区别

*在使用上主要是有无序/稳定否的差别

有序/稳定/在意内存->set/map
无序/快速查找添加删除/不担心高内存->unordered_set/map

set/map内部由红黑树实现

以map&unordered_map为例:

map是STL的一个关联容器,它提供一对一(第一个为key,每个key只能在map中出现一次,第二个为value)的数据处理能力。map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),所以在map内部所有的数据都是有序的,且map的查询、插入、删除操作的时间复杂度都是O(logN)。在使用时,map的key需要定义operator<。

unordered_map和map类似,都是存储的key-value的值,可以通过key快速索引到value。不同的是unordered_map不会根据key的大小进行排序,存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的。unordered_map的key需要定义hash_value函数并且重载operator==。

两者均按键查找

运行效率方面:unordered_map最高,而map效率较低但提供了稳定效率和有序的序列。

占用内存方面:map内存占用略低,unordered_map内存占用略高,而且是线性成比例的。

因而可以实现用空间换时间的优化操作。

但是并不是unordered_map查询时间一定比map短,因为实际情况中还要考虑到数据量,而且unordered_map的hash函数的构造速度也没那么快,所以不能一概而论,应该具体情况具体分析。哈希表的建立也比较耗费时间。

具体应用

例题:
在n个元素的数组中,找到差值为k的数字对去重后的个数
第一行:n——数字个数;k——差值
第二行:数字
Input:
5 2
1 5 3 4 2
Output:
3

#include 
#include 
using namespace std;
int n,k,x,ans=0;
unordered_set<int> myset;

int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        myset.insert(x);
    }
    for(int x:myset)
        if(myset.find(x+k)!=myset.end())
            ans++;
    cout<<ans<<endl;
    return 0;
}

Hiho:1494 一面砖墙
学习笔记:枚举与优化之unordered_set/map_第1张图片

#include 
#include 
using namespace std;
int n,x,t,st;
unordered_map<int,int> cnt;

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        st=0;
        for(int j=0;j<x;j++)
        {
            cin>>t;
            st+=t;
            if(j!=x-1)cnt[st]++;
        }
    }
    int mx=0;
    for(auto item:cnt)
        if(item.second>mx)
            mx=item.second;
    cout<<n-mx<<endl;
    return 0;
}

在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置

#include 
#include 
#include 
#include 
using namespace std;
int main()
{
    unordered_map<char,int> str;
    int n,i,f;
    char ch;
    i=0;
    f=0;
    char s[10005];
    while(ch=getchar(),ch!='\n')
    {
        s[i]=ch;
        ++str[ch];
        i++;
    }
    for(i=0;i<strlen(s);i++)
    {
        if(str[s[i]]==1)
        {
            printf("%d\n",i+1);
            f=1;
            break;
        }
    }
    if(f==0)printf("0\n");
    return 0;
}

牛客原题:
学习笔记:枚举与优化之unordered_set/map_第2张图片

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        if(str.empty()) return -1;
        unordered_map<char,int> strr;

       for (auto ch:str) strr[ch]++;

      for (int i=0;i<str.length();i++)
      {
          if(strr[str[i]]==1)
            return i;
      }
   	return 0;
    }
};

(待更新)

*参考链接:
https://blog.csdn.net/u010956473/article/details/77100750
https://blog.csdn.net/u013195320/article/details/23046305
https://blog.csdn.net/Blues1021/article/details/45054159
https://blog.csdn.net/u011475134/article/details/75810085
https://blog.csdn.net/qq_29108585/article/details/62905427
https://blog.csdn.net/weixin_39778570/article/details/80677688

你可能感兴趣的:(学习笔记)