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;
}
最终结果