unordered_map、unordered_set使用

实现机理

unordered_map内部实现了一个哈希表,也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用。因此,其元素<key,value>的排列顺序是无序的。
unordered_set底层也是哈希表,只是存储的是value,而不是<key,value>

待补充:

unordered_map使用

参考:
http://www.cplusplus.com/reference/unordered_map/unordered_map/
http://c.biancheng.net/view/530.html

  • 基本:初始化,增删改查;

类模板声明

template < class Key,                                    // unordered_map::key_type
           class T,                                      // unordered_map::mapped_type
           class Hash = hash<Key>,                       // unordered_map::hasher
           class Pred = equal_to<Key>,                   // unordered_map::key_equal
           class Alloc = allocator< pair<const Key,T> >  // unordered_map::allocator_type
           > class unordered_map;

注意: unordered_set和unordered_map本质上都是使用hash方法对元素进行存储和查找,而C++没有为vector,pair等定义默认hash方法,所以模板参数不能是vector,pair这类。除非你自己自定义一个对应的hash函数

头文件

#include < unordered_map >

初始化

//默认无参构造
explicit unordered_map ( size_type n = /* see below */,
/*size_type n: Minimum number of initial buckets.没有设定会自适应 */
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& alloc = allocator_type() );
explicit unordered_map ( const allocator_type& alloc );

//迭代器范围构造
template <class InputIterator>
  unordered_map ( InputIterator first, InputIterator last,
                  size_type n = /* see below */,
                  const hasher& hf = hasher(),
                  const key_equal& eql = key_equal(),
                  const allocator_type& alloc = allocator_type() );
//复制构造
unordered_map ( const unordered_map& ump );
unordered_map ( const unordered_map& ump, const allocator_type& alloc );
//移动语义的复制构造
unordered_map ( unordered_map&& ump );
unordered_map ( unordered_map&& ump, const allocator_type& alloc );
//初始化列表构造
unordered_map ( initializer_list<value_type> il,
                size_type n = /* see below */,
/*size_type n: Minimum number of initial buckets.没有设定会自适应 */,
                const hasher& hf = hasher(),
                const key_equal& eql = key_equal(),
                const allocator_type& alloc = allocator_type() );

示例:

// constructing unordered_maps
#include <iostream>
#include <string>
#include <unordered_map>

typedef std::unordered_map<std::string,std::string> stringmap;

stringmap merge (stringmap a,stringmap b) {
  stringmap temp(a); temp.insert(b.begin(),b.end()); return temp;
}

int main ()
{
  stringmap first;                              // empty
  stringmap second ( {{"apple","red"},{"lemon","yellow"}} );    // init list
  stringmap third ( {{"orange","orange"},{"strawberry","red"}} );  // init list
  stringmap fourth (second);                    // copy
  stringmap fifth (merge(third,fourth));        // move
  stringmap sixth (fifth.begin(),fifth.end());  // range

  std::cout << "sixth contains:";
  for (auto& x: sixth) std::cout << " " << x.first << ":" << x.second;
  std::cout << std::endl;

  return 0;
}

访问某个元素

先构造

//空的构造函数
 std::unordered_map<std::string, int> mymap0;

 //初始化列表构造
  std::unordered_map<std::string, int> mymap = { { "one", 1 }, { "two", 2 }, { "three", 3 } };

再访问

  1. 下标运算符中使用键来获取它所对应的值的引用,在下标中使用不存在的键时,会以这个键为新键生成一个新的元素,新元素的值是默认的。
mymap["one"]=0;//将"one"对应的值改为0
mymap["zero"];//会在mymap中增加一个键值对{"zero",0}
  1. 成员函数 at() 会返回参数所关联对象的引用,如果键不存在,会拋出一个 out_of_range 异常。所以当我们不想生成有默认对象的元素时,应该选择使用 at() 而不是下标运算符。
mymap.at("one")=1;//将"one"对应的值改为1
mymap.at("three");//拋出一个 out_of_range 异常

查找

  • count:通过key查找,找到返回1,找不到返回0。
size_type count ( const key_type& k ) const;
  • find():返回key对应的迭代器,如果key不存在,则find返回unordered_map::end因此可以通过判断map.find(key) == map.end()来判断,key是否存在于当前的unordered_map中,
iterator find ( const key_type& k );

注意: unordered_map中的value_type是pair对象,所以迭代器指向的是pair对象

关于pair和make_pair()的使用,参考:
https://blog.csdn.net/OceanLight/article/details/7890537?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase

template <class T1, class T2> struct pair
{
  typedef T1 first_type;
  typedef T2 second_type;
 
  T1 first;
  T2 second;
  pair() : first(T1()), second(T2()) {}
  pair(const T1& x, const T2& y) : first(x), second(y) {}
  template <class U, class V>
    pair (const pair<U,V> &p) : first(p.first), second(p.second) { }
}


template <class T1, class T2>
  pair<V1,V2> make_pair (T1&& x, T2&& y);  // see below for definition of V1 and V2
//The function returns:
template <class T1, class T2>
  pair<V1,V2> make_pair (T1&& x, T2&& y){
        return pair<V1,V2>(std::forward<T1>(x),std::forward<T2>(y))}


//使用示例
pair<int ,int >p (5,6);
//函数参数是pair时, make_pair()比较方便
pair<int ,int > p1= make_pair(5,6);

//unordered_map中的value_type如下
typedef pair<const Key, T> value_type;

unordered_map<Key,T>::iterator it= find ( const key_type& key );
it->first;       // key
it->second;     //  value)

遍历元素

  • 基于迭代器遍历输出
//auto自动识别为迭代器类型 
for (auto it = mymap.begin(); it != mymap.end(); ++it)
        std::cout << " " << it->first << ":" << it->second << std::endl;  

//注意如果用operator*(),则需要注意优先级,(*it)必须加括号,记住教训
for (auto it = mymap.begin(); it != mymap.end(); ++it)
        std::cout << " " <<(*it).first << ":" << (*it).second << std::endl;      
  • 基于范围的for循环,遍历元素
for (auto& x : mymap) {
        std::cout << x.first << ": " << x.second << std::endl;
    }
  • 查看每个bucket中的元素
    std::cout << "mymap's buckets contain:\n";
    for (unsigned i = 0; i < mymap.bucket_count(); ++i) {
        std::cout << "bucket #" << i << " contains:";
        for (auto local_it = mymap.begin(i); local_it != mymap.end(i); ++local_it)
            std::cout << " " << local_it->first << ":" << local_it->second;
        std::cout << std::endl;
   }

插入

注意: map中的value_type是pair对象,所以迭代器指向的是pair对象

pair<iterator,bool> insert ( const value_type& val );
template <class P>
    pair<iterator,bool> insert ( P&& val );

返回值为pair<set::iterator, bool>
iterator表示该元素的位置 ,
bool 为true,表示插入成功(即原来set中没有此插入的元素)
bool为false,表示插入失败(即原来set中已存在此插入的元素)

关于pair和make_pair()的使用,参考:
https://blog.csdn.net/OceanLight/article/details/7890537?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase

//定义插入元素,类型为pair的对象
std::pair<std::string,int> item("four",4);
mymap.insert(item);

//利用make_pair<std::string,int>插入
mymap.insert(std::make_pair<std::string,int>("five",5);

//范围插入
unordered_map<std::string,int> yourmap{{"ten",10},{"eleven",11},{"twelve",12}};
mymap.insert(yourmap.begin(),yourmap.end());

// 初始化列表插入
mymap.insert({{"thirteen",13},{"fourteen",14}});

删除

    // 通过迭代器删除
    mymap.erase(mymap.begin());
    
    // 通过 Key 值删除
    mymap.erase("one");
    
    // 通过迭代器范围删除
    mymap.erase(mymap.find("three"), mymap.end());

   //清空mymap容器
   mymap.clear();

leetcode例题

  1. 多数元素
    给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
示例 1:
输入: [3,2,3]
输出: 3

示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2

最简单的一种方法就是利用哈希表统计元素出现的频率,然后找出出现频率最大的那个元素

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        unordered_map<int,int> counts;
        int majority,max=0;
        for(auto i:nums){
        counts[i]++;
        if(counts[i]>max){
            max=counts[i];
            majority=i;
        }
        }
        return majority;
    }
};

unordered_set使用

类模板声明

template < class Key,                        // unordered_set::key_type/value_type
           class Hash = hash<Key>,           // unordered_set::hasher
           class Pred = equal_to<Key>,       // unordered_set::key_equal
           class Alloc = allocator<Key>      // unordered_set::allocator_type
           > class unordered_set;

注意: unordered_set和unordered_map本质上都是使用hash方法对元素进行存储和查找,而C++没有为vector,pair等定义默认hash方法,所以模板参数不能是vector,pair这类。除非你自己自定义一个对应的hash函数

头文件

#include<unordered_set>

初始化

参考:http://www.cplusplus.com/reference/unordered_set/unordered_set/unordered_set/

//默认无参构造
explicit unordered_set ( size_type n = /* see below */,
/*size_type n: Minimum number of initial buckets.没有设定会自适应 */
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& alloc = allocator_type() );
//迭代器范围构造
template <class InputIterator>
         unordered_set ( InputIterator first, InputIterator last,
                         size_type n = /* see below */,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& alloc = allocator_type() );
//复制构造
unordered_set ( const unordered_set& ust );
unordered_set ( const unordered_set& ust, const allocator_type& alloc );
//移动语义的复制构造
unordered_set ( unordered_set&& ust );
unordered_set ( unordered_set&& ust, const allocator_type& alloc );
//初始化列表
unordered_set ( initializer_list<value_type> il,
                size_type n = /* see below */,
                const hasher& hf = hasher(),
                const key_equal& eql = key_equal(),
                const allocator_type& alloc = allocator_type() );
  • 使用示例
// constructing unordered_sets
#include <iostream>
#include <string>
#include <unordered_set>

template<class T>
T cmerge (T a, T b) { 
    T t(a); 
    t.insert(b.begin(),b.end()); 
    return t; 
    }

int main ()
{
  std::unordered_set<std::string> first;                                // empty
  std::unordered_set<std::string> second ( {"red","green","blue"} );    // init list
  std::unordered_set<std::string> third ( {"orange","pink","yellow"} ); // init list
  std::unordered_set<std::string> fourth ( second );                    // copy
  std::unordered_set<std::string> fifth ( cmerge(third,fourth) );       // move
  std::unordered_set<std::string> sixth ( fifth.begin(), fifth.end() ); // range

  std::cout << "sixth contains:";
  for (const std::string& x: sixth) std::cout << " " << x;
  std::cout << std::endl;

  return 0;
}

查找

可以访问,不能修改,可以删除

  • find, 找到,返回iterator;没有找到,返回end()。
 iterator find ( const key_type& k );
//示例
std::unordered_set<std::string> nums({"one","two","three"});
std::unordered_set<std::string>::const_iterator it=nums.find("one");
if ( it == nums.end() )
    std::cout << "not found in nums";
else
    std::cout << *it << " is in nums";
  • count,找到,返回1;没有找到,返回0。
size_type count ( const key_type& k ) const;

//使用示例
std::unordered_set<std::string> nums({"one","two","three"});
if (nums.count("one")>0)
      std::cout << "nums has " << x << std::endl;
else
      std::cout << "nums has no " << x << std::endl;

遍历

  • 基于迭代器
    由于unordered_set内部是无序的,所以begin(),end()就只保证从begin()到end()的范围覆盖了所以元素
std::unordered_set<std::string> nums({"one","two","three"});
for ( auto it = nums.begin(); it != nums.end(); ++it )
    std::cout << " " << *it;
  • 基于for范围循环遍历
for(auto& i:nums)
    cout<<" "<<i;
  • 遍历bucket中的元素
  for ( unsigned i = 0; i < nums.bucket_count(); ++i) {
    std::cout << "bucket #" << i << " contains:";
    for ( auto local_it = nums.begin(i); local_it!= nums.end(i); ++local_it )
      std::cout << " " << *local_it;
  }

插入

  • insert
    返回值为pair<set::iterator, bool>
    iterator表示该元素的位置 ,
    bool 为true,表示插入成功(即原来set中没有此插入的元素)
    bool为false,表示插入失败(即原来set中已存在此插入的元素)

关于pair和make_pair()的使用,参考:
https://blog.csdn.net/OceanLight/article/details/7890537?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase

//插入值
pair<iterator,bool> insert ( const value_type& val );
pair<iterator,bool> insert ( value_type&& val );

//从建议的位置hint开始搜索插入点, 一般不用
iterator insert ( const_iterator hint, const value_type& val );
iterator insert ( const_iterator hint, value_type&& val );

//范围插入
template <class InputIterator>
    void insert ( InputIterator first, InputIterator last );
//插入初始化列表
void insert ( initializer_list<value_type> il );
std::unordered_set<std::string> nums({"one","two","three"});
nums.insert("four");
nums.insert({"five","six"});

删除

  • erase
//通过位置删除
iterator erase ( const_iterator position );
//通过key删除
size_type erase ( const key_type& k );
//范围删除
iterator erase ( const_iterator first, const_iterator last );
  • clear()
    清空

leetcode例题

653. 两数之和 IV - 输入 BST

给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
在这里插入图片描述
方法: 使用 unordered_set,一次遍历
设给定的和为k,对于每个值为 p 的节点,在 unordered_set 中检查是否存在k−p。如果存在,那么可以在该树上找到两个节点的和为 k;否则,将 p 放入到 unordered_set 中。
如果遍历完整棵树都没有找到一对节点和为 k,那么该树上不存在两个和为 k 的节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool findTarget(TreeNode* root, int k) {
        //unordered_set 一次遍历
        unordered_set<int> ans;
        return findTargetCore(root,ans,k);
        
    }
    bool findTargetCore(TreeNode* root,unordered_set<int> &ans,int k){
        if(root==NULL)
            return false;
        if(ans.find(k-root->val)!=ans.end())
            return true;
        ans.insert(root->val);
        return findTargetCore(root->left,ans,k)||findTargetCore(root->right,ans,k);
    }
};

1496. 判断路径是否相交

1496. 判断路径是否相交
给你一个字符串 path,其中 path[i] 的值可以是 ‘N’、‘S’、‘E’ 或者 ‘W’,分别表示向北、向南、向东、向西移动一个单位。

机器人从二维平面上的原点 (0, 0) 处开始出发,按 path 所指示的路径行走。

如果路径在任何位置上出现相交的情况,也就是走到之前已经走过的位置,请返回 True ;否则,返回 False 。

1 <= path.length <= 10^4
path 仅由 {‘N’, ‘S’, ‘E’, 'W} 中的字符组成

class Solution {
public:
    vector<int> nextPos(int x,int y,char c){
        if(c=='N'){
            return {x,y+1};
        }else if(c=='S'){
            return {x,y-1};
        }else if(c=='E'){
            return {x+1,y};
        }else{
            return {x-1,y};
        }
    }

    bool isPathCrossing(string path) {
        //利用unordered_map记录走过的坐标
        int N=path.size();
        if(0==N) return false;
        //这两种用法都不支持,没有对应的hash函数
        //unordered_set<pair<int,int>> ms;
        //unordered_set<vector<int>> ms;
        //曲线救国,将x,y转成字符串总行了吧
        
        unordered_set<string> ms;
        ms.insert("00");
        int x=0,y=0;
        for(int i=0;i<N;i++){
            vector<int> nextP=nextPos(x,y,path[i]);
            x=nextP[0];
            y=nextP[1];
            if(ms.count(to_string(x)+to_string(y)))
                return true;
            else
                ms.insert(to_string(x)+to_string(y));
        }
        return false;
    }
};
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值