map与set的基本应用

来源:互联网 发布:沈航网络自助 编辑:程序博客网 时间:2024/06/16 12:14

map与set的使用与原理


set

这里写图片描述
一种底层为二叉搜索树中红黑树的C++标准容器,其模板参数有三个: T(存储在容器中的关键词的数据类型)、Compare((提供比较元素的函数决定元素在容器中的相对位置)、Alloc(存储管理设备)。

成员变量

这里写图片描述

成员函数

这里写图片描述
这里写图片描述

这里对set的部分函数功能进行测试说明
首先,进行基本的 添加数据、迭代器的建立与使用。

#include<iostream>using namespace std;#include<set>void TestSet(){    set<int> s1;    s1.insert(5);    s1.insert(2);    s1.insert(0);    s1.insert(1);    s1.insert(6);    set<int>::iterator it1 = s1.begin();    while (it1 != s1.end())    {        cout << *it1 << " ";        ++ it1;    }    cout << endl;}int main(){    Test();    return 0;}

调试运行后结果显示为:
这里写图片描述

set中迭代器的++与–重载使用的是 中序遍历 进行移动,从而我们打印时得到一个顺序的结果,而当我们改变Compare,进行一个greater的重载并手动调用时,可实现降序的打印

typedef set<int,greater<int>> Set;void TestSet(){    Set s1;    s1.insert(5);    s1.insert(2);    s1.insert(0);    s1.insert(1);    s1.insert(6);    Set::iterator it1 = s1.begin();    while (it1 != s1.end())    {        cout << *it1 << " ";        ++ it1;    }    cout << endl;}

这里写图片描述

并且,set还具有 防冗余功能,当对6进行重复插入时

    Set s1;    s1.insert(5);    s1.insert(2);    s1.insert(0);    s1.insert(1);    s1.insert(6);    s1.insert(6);    s1.insert(6);    s1.insert(6);

这里写图片描述

仍然只有一个6被记录,这里是由于Insert的返回值为 pair类型

这里写图片描述

pair为一个具有两个模板参数的结构体

这里写图片描述
在进行插入时,若在原容器中查到了当前添加内容,则pair中第二个参数会返回false表示已经存在一个当前内容。
而我们也可以看到Insert中也存在两个重载,分别 可以进行指定位置插入并返回一个指向位置的定位器、特定区间插入,将两哥迭代器中的内容插入;

int pos = 10;    for (int pos = 0; pos < 14; pos++)        s1.insert(s1.end()--, pos);

这里写图片描述

Set s1;    s1.insert(5);    s1.insert(2);    s1.insert(0);    s1.insert(1);    s1.insert(6);    vector<int> v1;    v1.insert(v1.begin(),99);    v1.insert(v1.begin(), 98);    v1.insert(v1.begin(), 97);    s1.insert(v1.begin(), v1.end());

这里写图片描述

map

map与set有很多相同之处,因此这里着重介绍两者的差异
map存储的为一对数据K,V,而set为一个数据K。

void TestMap(){    map<string, int> m1;    m1.insert(pair<string, int>("const", 0));    m1.insert(pair<string, int>("set", 0));    m1.insert(pair<string, int>("air", 0));    m1.insert(pair<string, int>("map", 0));    map<string, int>::iterator it1 = m1.begin();    while (it1 != m1.end())    {        cout << it1->first << ":" << it1->second << endl;        ++it1;    }}int main(){    TestMap();    return 0;}

这里写图片描述

也因此map在使用是可以重复输入,将 多次出现的数据次数记以进第二个参数位置 ,我们可以进行一些统计工作,譬如单词出现的次数:

①使用find函数,当发现已经存在数据时进行加一

string str[] = { "one", "two", "four", "four", "two", "four", "four" };    map<string, int> CountMap;    for (size_t i = 0; i < sizeof(str) / sizeof(str[0]); i++)    {        map<string, int>::iterator it = CountMap.find(str[i]);        if (it != CountMap.end())            (*it).second++;    }

当然我们在set中曾提过,Insert的返回值也为一对数据切插入失败时会在第二个数据返回false,由此进行优化:
②利用Insert的返回值

void TestMap(){    string str[] = { "one", "two", "four", "four", "two", "four", "four" };    map<string, int> CountMap;    pair<map<string, int>::iterator, bool> ret;    for (size_t i = 0; i < sizeof(str) / sizeof(str[0]);i++)    {        ret = CountMap.insert(pair<string,int>((str[i]), 1));        if (ret.second == false)            ret.first->second++;    }    map<string, int>::iterator it1 = CountMap.begin();    while (it1 != CountMap.end())    {        cout << it1->first << ":" << it1->second << endl;        ++it1;    }}int main(){    TestMap();    return 0;}

这里写图片描述

然而在map中,已经对这种操作进行了整理,放在了 [ ]的重载中,其底层实现与我们的第二种方法完全一致

这里写图片描述
这里写图片描述
③使用[ ]的重载

string str[] = { "one", "two", "four", "four", "two", "four", "four" };    map<string, int> CountMap;    for (size_t i = 0; i < sizeof(str) / sizeof(str[0]);i++)    {        CountMap[str[i]]++;    }

如此也可以得到与②同样的结果


简单应用

eg:求水果出现的次数且求出前N个最多的

首先由上述map中的方法,可以进行次数统计

int main(){    map<string, int> map1;    vector<map<string, int>::iterator> v;    string strs[] = { "葡萄", "梨", "桃", "西瓜", "菠萝", "西瓜", "梨", "橘子", "香蕉", "梨", "香蕉","椰子", "梨", "苹果", "菠萝", "香蕉", "橘子", "桃子", "苹果", "桃", "橘子", "葡萄", "橘子", "荔枝", "苹果", "荔枝", "橘子" };    for (size_t i = 0; i < sizeof(strs)/sizeof(strs[0]); i++)    {        map1[strs[i]]++;    }        return 0;}

接下来只需要将map1中的水果根据value,即第二个参数进行排序即可,方法众多,下文使用堆排序进行处理

typedef struct Compare{    bool operator()(map<string, int>::iterator l, map<string, int>::iterator r)    {        return l->second > r->second;    }}Compare;void GetTopN(map<string, int>& m, size_t n, vector<map<string, int>::iterator>& v){    map<string, int> ::iterator it = m.begin();    for (size_t i = 0; i < n; ++i)    {        v.push_back(it);        it++;    }    make_heap(v.begin(), v.end(), Compare());    while (it != m.end())    {        if (it->second > v.front()->second)        {            pop_heap(v.begin(), v.end(), Compare());            v.pop_back();            v.push_back(it);            push_heap(v.begin(), v.end(), Compare());        }        it++;    }}

使用堆排序将前N种水果插入,最后打印vector容器中的元素即可
在主函数中调用并打印

GetBeginOfNFruits(map1, 5, v);    for (size_t i = 0; i < v.size(); ++i)    {        cout << v[i]->first << "-" << v[i]->second << endl;    }

最终结果

这里写图片描述

2 0
原创粉丝点击