map和set

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;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值