STL中的无序容器

40 篇文章 0 订阅
9 篇文章 0 订阅

种类

  1. unordered_set (C++11)
  2. unordered_map (C++11)
  3. unordered_multiset (C++11)
  4. unordered_multimap (C++11)

上述四种容器采用哈希表实现。

不同操作的时间复杂度为:

插入:O(1),最坏情况O(N)。
查询:O(1),最坏情况O(N)。
删除:O(1),最坏情况O(N)。

记住,如果你采用合适的哈希函数,你可能永远不会看到最坏情况。

操作汇总

unordered_set

例子:

#include <unordered_set>
#include <iostream>

namespace ClassFoo{
void PrintIntDoubleUnOrderedSet(std::unordered_set<int>& m, char* pre) {
    std::unordered_set<int>::iterator it;
    std::cout << pre;
    for ( it = m.begin(); it != m.end(); it++ )
        std::cout << *it << " ";
    std::cout << std::endl;
}
void UnOrderedSetExample1() {
    std::unordered_set<int> foo1;


    // 普通插入
    foo1.insert(1);

    // 带暗示插入,std::pair<int,double>等价于上述的
    // std::unordered_set<int,double>::value_type
    foo1.insert(foo1.end(),2);

    // 插入一个范围
    std::unordered_set<int> foo2;
    foo2.insert(3);
    foo2.insert(4);
    foo2.insert(5);
    foo1.insert(foo2.begin(),foo2.end());

    PrintIntDoubleUnOrderedSet(foo1,"插入元素后的foo1:");

    // 查找主键4
    std::unordered_set<int>::iterator it;
    it = foo1.find(4);
    if( it != foo1.end() )
    {
        std::cout << "foo1.find(4):";
        std::cout << *it << std::endl;
    }

    // 删除上述找到的元素
    if( it != foo1.end() )
    {
        foo1.erase(it);
    }
    PrintIntDoubleUnOrderedSet(foo1,"删除主键为4的元素后的foo1:");

    // 遍历删除主键为2的元素
    for(it = foo1.begin();it != foo1.end();it++)
    {
        //遍历删除主键等于2
        //注意,删除元素会使迭代范围发生变化
        if ( *it == 2 )
        {
            foo1.erase(it);
            break;
        }
    }

    // 内部数据
    std::cout << "bucket_count:" << foo1.bucket_count() << std::endl;
    std::cout << "max_bucket_count:" << foo1.max_bucket_count() << std::endl;
    std::cout << "bucket_size:" << foo1.bucket_size(0) << std::endl;
    std::cout << "load_factor:" << foo1.load_factor() << std::endl;
    std::cout << "max_load_factor:" << foo1.max_load_factor() << std::endl;

    PrintIntDoubleUnOrderedSet(foo1,"删除主键为2的元素后的foo1:");
    foo1.clear();
    PrintIntDoubleUnOrderedSet(foo1,"清空后的foo1:");
}
}
int main( )
{
    ClassFoo::UnOrderedSetExample1();
    return 0;
}

unordered_map

// num2pos是unordered_map
#include<iostream>
#include<stdlib.h> 
#include<vector>
#include<unordered_map>

using namespace std;

class RandomizedSet {
public:
    RandomizedSet() {}

    bool insert(int val) {
        // 判断key=val是否存在
        if(num2pos.count(val)) return false;
        nums.push_back(val);
        num2pos[val] = nums.size() - 1;
        return true;
    }

    bool remove(int val) {
        if(!num2pos.count(val)) return false;
        int last = nums.back();
        num2pos[last] = num2pos[val];
        nums[num2pos[val]] = last;
        nums.pop_back();
        // 删除key=val
        num2pos.erase(val);
        return true;
    }

    int getRandom() {
        return nums[rand() % nums.size()];
    }

private:
    vector<int> nums;
    unordered_map<int, int> num2pos;    

};

int main() {
    RandomizedSet obj;
    bool param_1 = obj.insert(1);
    bool param_2 = obj.remove(1);
    bool param_4 = obj.insert(2);
    int param_3 = obj.getRandom();
    cout<<param_3<<endl;
    return 0;
}
#include <iostream>
#include <unordered_map>
#include <string>
int main(int argc, char **argv) {
    std::unordered_map<int, std::string> map;
    map.insert(std::make_pair(1, "Scala"));
    map.insert(std::make_pair(2, "Haskell"));
    map.insert(std::make_pair(3, "C++"));
    map.insert(std::make_pair(6, "Java"));
    map.insert(std::make_pair(14, "Erlang"));
    if(map[14] != "Erlang") return 1;
    std::unordered_map<int, std::string>::iterator it;
    if ((it = map.find(6)) != map.end()) {
        std::cout << it->second << std::endl;
    }
    return 0;
}
#include <iostream>
#include <map>

using namespace std;

int main() {
    map<int,string> student;
    student.insert(pair<int,string>(2,"li"));
    student.insert(pair<int,string>(1,"wang"));
    student.insert(pair<int,string>(3,"sun"));
    for(auto &v : student) // for(auto v : student)也是可以的
        cout<<"key: "<<v.first<<" | value: "<<v.second<<endl;
    return 0;
}

以unordered_map为例讲解(unordered_set…同理)

  1. map
    内部数据的组织,基于红黑树实现,红黑树具有自动排序的功能,因此map内部所有的数据,在任何时候,都是有序的。

  2. hash_map(非标准,以后用就用unordered_map
    基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存。
    插入操作:得到key -> 通过hash函数得到hash值 -> 得到桶号(hash值对桶数求模) -> 存放key和value在桶内
    取值过程:得到key -> 通过hash函数得到hash值 -> 得到桶号(hash值对桶数求模) -> 比较桶内元素与key是否相等 -> 取出相等纪录的value
    当每个桶内只有一个元素时,查找时只进行一次比较,当很多桶都没有值时,查询更快。
    用户可以指定自己的hash函数与比较函数。

  3. unordered_map
      C++ 11标准中加入了unordered系列的容器。unordered_map记录元素的hash值,根据hash值判断元素是否相同。map相当于java中的TreeMap,unordered_map相当于HashMap。无论从查找、插入上来说,unordered_map的效率都优于hash_map,更优于map;而空间复杂度方面,hash_map最低,unordered_map次之,map最大。

速度:unordered_map>hash_map>map

注意:对于STL里的map容器,count方法与find方法,都可以用来判断一个key是否出现,count统计的是key出现的次数,因此只能为0/1,而find基于迭代器实现,以mp.end()判断是否找到要求的key。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值