map和set

来源:互联网 发布:从底层看java中的接口 编辑:程序博客网 时间:2024/06/10 19:17

map和set是两个主要的关联容器,但是底层都是红黑树实现
map
STL中关于map的理解:
map特性是,所有元素都会根据元素的键值自动排序,map的所有元素都是pair(结构体),同时有键值key和实值value。pair的第一个元素被视为键值,第二个元素视为实值,map不允许两个元素拥有相同的键值;
pair的定义:

template<class K,class V>struct Pair{    K _first;    V _second;    Pair(const K&key, const V&value)        :_first(key)        , _second(value)    {}};

一:实现一个简单的字典插入,删除,查找

void TestDic(){map<string, string> dict;//插入dict.insert(make_pair("insert", "插入"));dict.insert(make_pair("find", "查找"));dict.insert(make_pair("erase", "删除"));PrintfMap(dict);//查找map<string, string> ::iterator it = dict.find("find");if(it ==dict.end()){    cout << "no found" << endl;}else{    cout << "found" << endl;}//删除map<string, string> ::iterator it1 = dict.find("erase");if (it1 == dict.end()){    cout << "no found" << endl;}else{    dict.erase(it1);}PrintfMap(dict);}

二:map统计计数(TopK问题)
如:最喜欢吃的水果:

void TestTopk(){    //方法一:    map<string, int> CountMap;    string fruits[] = { "苹果", "葡萄", "梨", "香蕉", "葡萄", "苹果", "葡萄", "苹果", "葡萄", "苹果", "苹果", };    for (size_t i = 0; i < sizeof(fruits)/sizeof(fruits[0]); ++i)    {        map<string, int>::iterator ret = CountMap.find(fruits[i]);        if (ret != CountMap.end())        {            ret->second++;        }        else//第一次出现        {            CountMap.insert(make_pair(fruits[i], 1));        }    }}

这里写图片描述
方法一的特点效率低,如果不存在,查找了两次;
方法二:

void TestTopk(){    //调pair<iterator, bool> insert(const value_type& val);    /*    insert 插入成功return pair,return false表明已经有节点存在    */    /*map<string, int> CountMap;    string fruits[] = { "苹果", "葡萄", "梨", "香蕉", "葡萄", "苹果", "葡萄", "苹果", "葡萄", "苹果", "苹果", };    for (size_t i = 0; i < sizeof(fruits) / sizeof(fruits[0]); ++i)    {         pair<map<string, int> ::iterator, bool> pr = CountMap.insert(make_pair(fruits[i], 1));        if (pr.second == false) //已经存在++计数        {            pr.first->second++;        }    }}

方法二的比方法一的效率高,只查找了找了一次;
方法三:

void TestTopk(){   map<string, int> CountMap;    string fruits[] = { "苹果", "葡萄", "梨", "香蕉", "葡萄", "苹果", "葡萄", "苹果", "葡萄", "苹果", "苹果", };    for (size_t i = 0; i < sizeof(fruits) / sizeof(fruits[0]); ++i)    {        CountMap[fruits[i]]++;    }}

如果前年的两种比较容易理解,那么这种方法会比较那理解,它是如何实现统计计数呢?
调用operator[]来实现

V&operator[](const k&key){ return (*((this->insert(make_pair(k,mapped_typed()))).first)).second;}

我们一层一层来分析:
1:mapped_typed()相当于调用V的缺省构造函数;
2:make_pair是pair的构造函数;里面有两个参数first和second;
3: first表示是迭代器,second表示是value;
4: 插入是insert返回值是pair;*解引用;取里面的数据;
5:如果没有则进行插入,如果存在把&value的值返回;
operator[]应用插入和修改

void PrintfMap(const map<string, string>&dict){    map<string, string>::const_iterator it = dict.begin();    while (it!=dict.end())    {        cout << (*it).first << ":" << it->second << endl;        ++it;    }    cout << endl;}//operator[]的作用是插入和修改实现字典:void TestMapDict(){    map<string, string> dict;    dict["sort"] = "排序";    dict["insert"] = "插入";    dict["left"] = "左边";    dict["sort"] = "***";    PrintfMap(dict);}

这里写图片描述
前面我们了解到Topk的几种算法,但我们希望统计最喜欢吃的水果的次数,按照排序跟家直观;那么怎样能够快速排序呢?
三:排序的几种常见算法:
在前面我们知道
堆排序,优先级队列;http://blog.csdn.net/f2016913/article/details/68483000
这里我们主要看map和set的实现:
1:map实现排序

void TestTopk(){    map<string, int> Countmap;    string fruits[] = { "苹果", "葡萄", "梨", "香蕉", "葡萄", "苹果", "葡萄", "苹果", "葡萄", "苹果", "苹果", };    for (size_t i = 0; i < sizeof(fruits) / sizeof(fruits[0]); ++i)    {        Countmap[fruits[i]]++;    }    vector<map<string, int>::iterator> v;    map<string, int>::iterator CountIt = Countmap.begin();    while (CountIt!=Countmap.end())    {        v.push_back(CountIt);        ++CountIt;    }    //仿函数    struct Compare    {        bool operator()(map<string, int>::iterator l, map<string, int>::iterator r)        {            return l->second > r->second;        }    };    sort(v.begin(), v.end(), Compare());}

这里写图片描述
2:Multimap实现:

void TestMultimap(){typedef multimap<string, string> Dict;    typedef multimap<string, string>::iterator DictIt;    Dict dict;    dict.insert(make_pair("sort", "排序"));    dict.insert(make_pair("sort", "排序"));    dict.insert(make_pair("sort", "排序"));    dict.insert(make_pair("left", "左边"));    dict.insert(make_pair("left", "剩余"));    DictIt  it = dict.begin();    while (it!=dict.end())    {        cout << it->second << " ";        ++it;    }    cout << endl;}

这里写图片描述
multimap特性以及用法与map完全相同,唯一的差别在于:
1. 允许重复键值的元素插入容器(使用了RB-Tree的insert_equal函数)
2. 键值key与元素value的映照关系是多对多的关系
3. 没有定义[]操作运算
3:set实现:
set的特性是,所有元素会根据元素的键值自动排序,set元素不想map那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,set不允许两个相同的键值;

void Testset(){    set<int> s;    s.insert(1);    s.insert(1);    s.insert(1);    s.insert(1);    s.insert(1);    s.insert(4);    s.insert(2);    s.insert(3);    s.insert(5);    set<int> ::iterator it = s.begin();    while (it!=s.end())    {        cout << *it << " ";        ++it;    }    cout << endl;}

这里写图片描述
set不仅会排序,而且会去重
4:mulitiset的实现:
mulitise的特性以及用法和set完全相同,唯一的差别是允许键值的重复

void Testmultiset(){multiset<int> s;    s.insert(1);    s.insert(1);    s.insert(1);    s.insert(1);    s.insert(1);    s.insert(4);    s.insert(2);    s.insert(3);    s.insert(5);    set<int> ::iterator it = s.begin();    while (it!=s.end())    {        cout << *it << " ";        ++it;    }    cout << endl;}

这里写图片描述

0 0
原创粉丝点击