按关键字有序保存元素:
无序集合:
map是关键字-值对的集合。被称为无序数组,即通过关键字即可查找到对应的值。
通过map来统计单词在输入中出现的次数:
map<string, size_t> word_count;
string word;
while (cin >> word)
{
++word_count[word];
}
for (const auto& x : word_count)
{
cout << x.first << " occurs " << x.second << ((x.second > 1) ? " times" : " time") << endl;
}
set存储关键字,是关键字的集合。
使用set来忽略常见的单词:
map<string, size_t> word_count;
set<string> exclude{ "the","woaini","666","hhh","adaasa","dawdadadas","ylh","dwadada"};
string word;
while (cin >> word)
{
//找到返回word,没找到返回尾后迭代器
if (exclude.find(word) == exclude.end())
{
++word_count[word];
}
}
for (const auto& x : word_count)
{
cout << x.first << " occurs " << x.second << ((x.second > 1) ? " times" : " time") << endl;
}
使用一个关键字类型和值类型来定义map,只需一个关键字来定义set。
默认构造函数:创建一个空容器。
初始化同类型的拷贝。
使用值范围来初始化关联容器。
也可以进行值初始化,列表初始化。
map<string, string> a{
{"ylh","da"},
{"dad","oid"},
{"oda","cece"} };
set<string> b{ "wad","Da","grg","plda" };
允许有重复关键字:
map和set如果有多个关键字,则会跳过;multimap和multiset会继续存储
·vector<int> a;
for (size_t i = 0; i != 10; ++i)
{
a.push_back(i);
a.push_back(i);
}
set<int> b1{ a.cbegin(),a.cend() }; //set.size()= 10
multiset<int> b2{ a.cbegin(),a.cend() }; //multiset.size()= 20
map存储姓氏和家庭成员的名字: 支持添加新成员和插入:
map<string,vector<string>> family;
string first_name,child_name;
while ( [&]()->bool {cout<<"请输入家庭的姓:"; return cin>>first_name && (first_name != "end");}() )
{
cout<<"请输入孩子的名字:";
while (cin>>child_name && (child_name != "end"))
{
family[first_name].push_back(child_name);
}
}
for (auto it = peo.cbegin(); it != peo.cend(); ++it)
{
cout << (*it).first << ": ";
for_each((*it).second.begin(), (*it).second.end(), [](const string& str) {cout << str << " "; });
cout << endl;
}
include < utility > 头文件
一个pair保存两个数据成员。
pair用来生成特定类型的模板,创建一个pair:提供两个类型名。pair的数据成员将具有对应的类型。
pair<string, string> a;
pair<string, size_t> b;
pair<string, list<size_t>> c;
当然也可以进行值初始化。
pair的成员被命名为first和second,是共有的。普通的成员访问符号可以直接访问。
pair类型的函数返回值:
pair<string, int> process(vector<string>& v)
{
if (!v.empty())
{
return { v.back(),v.back().size() }; //显式列表初始化
}
else
{
return pair<string, int>(); //隐式构造返回值
}
}
pair被其他容器包含的情况:
vector的元素为pair,pair再隐式或显式构造对象
vector<pair<string, int>> a;
string temp;
int num;
while (cin >> temp >> num)
{
a.push_back({ temp,num }); //隐式构造
}
补充:利用vector构造pair元素对象的几种方式:
a.push_back({ temp,num }); //隐式构造
a.push_back(pair<string, int>{temp, num}); //显式构造
a.push_back(make_pair(temp, num)); //make_pair构造
a.emplace_back(temp, num); //emplace_back构造函数
示例:在用map存储姓氏和名字的基础上,使用pair存储名字和生日
使用lamdba表达式更快捷
lamdba表达式采用&捕获引用,指明返回类型**,最后有一个小括号表示要传递的形参数值,此题中不用传递形参,所以此处为空。**
打印的方式:可以采用二维数组的方式打印:
首先由map得到 string和 vector容器,打印string;在由vector容器得到pair类型,再有pair的first和second得到结果。
map<string, vector<pair<string,string>>> peo; //姓: 名字和生日
string fname, name, birth;
int choice = 0;
while ([&]()->bool {cout << "请输入家庭姓氏: "; return (cin >> fname) && (fname != "quit"); }())
{
while ([&]()->bool {cout << "请输入姓名: "; return (cin >> name) && (name != "quit"); }())
{
if ([&]()->bool {cout << "请输入生日: "; return (cin >> birth) && (birth != "quit"); }())
{
peo[fname].emplace_back(name, birth);
}
}
}
cout << endl;
for (const auto& i : peo)
{
cout << i.first << ": " << endl;
for (const auto& y : i.second)
{
cout << y.first << ", " << y.second << endl;
}
}
set和map关键字和值的类型:
迭代器map_it指向map的第一个元素,解引用迭代器得到一个pair的引用,pair的first为const,second可以修改。
map<string, int> a{ {"ylh",666} };
auto map_it = a.begin(); //map的迭代器
cout << map_it->first << " " << map_it->second << endl;
map_it->first = "woaini"; //错误,关键字是const
++map_it->second; //可以递增迭代器改变元素
set: set关键字只读,无法修改。
set<int> a{ 1 };
auto set_it = a.begin();
++(* set_it) //错误,set关键字只读
map和set的遍历:
for (auto it=a.cbegin();a!=a.cend();++a)
{
cout<<(*it).first<<" "<<it->second<<endl;
}
注意:使用set,map,multiset,multimap遍历时,迭代器按关键字升序遍历元素。
ps:通常不对关联容器使用泛型算法。
set中使用insert:
vector<int> a{ 2,4,6,8,10 };
set<int> set2;
set2.insert(a.cbegin(), a.cend()); //5个
set2.insert({ 1,3,5,7,1,3,5,7 }); //4个
//总共9个
map中使用insert:(和创建pair类型的对象一样)
map<string, int> a;
a.insert(pair<string, int>{"ylh", 666}); //显式构造pair
a.insert({ "word",111 }); //初始化列表
a.insert(make_pair("word", 222)); //make_pair构造
a.insert(map<string, int>::value_type{ "word",333 }); //构造一个pair,并且构造一个对象
map和set的insert或者emplace返回一个 pair类型。
pair的first成员是一个迭代器,指向已经具有的关键字的元素;
pair的second成员是一个bool值,指出插入成功,还是已经存在于容器。
map<string,int> a;
a.insert({ "word",111 });
auto it=a.insert(make_pair("word", 222));
//it的first指向已经具有的关键字的元素。 second表示bool。
cout << (it.first)->first << " " << (it.first)->second << " " << it.second;
//分别打印: word 111 0
insert返回值的完整类型:pair包含一个map的迭代器与bool
pair<map<string,int>::iterator,bool> it=a.insert(make_pair(word,1));
允许一个关键字有多个对应的值。
multimap<string, int> a;
a.insert(pair<string, int>{"ylh", 666});
a.insert({ "word",111 });
a.insert(make_pair("word", 222));
a.insert(map<string, int>::value_type{ "word",333 });
单词计数,利用insert的返回值来递增关键字的值的计数。
++word_count.insert({ word,0 }).first->second;
/*auto it = word_count.insert(make_pair(word, 1));
if (!it.second)
{
++it.first->second;
}*/
一个程序:思考这个程序打印能否使用for_each或者copy算法???
vector<size_t> temp{ 1,2,3,4,5,6 };
map<string, vector<size_t>> a;
string word = "word";
pair<map<string, vector<size_t>>::iterator, bool> it = a.insert(make_pair(word,temp));
for (auto it = a.cbegin(); it != a.cend(); ++it)
{
cout << it->first << " "; //得到string
for (auto it2 = it->second.cbegin(); it2 != it->second.cend(); ++it2)
{
cout << *it2 << " ";
}
cout << endl;
}
//for_each(a.cbegin()->first, a.cbegin()->first, [](const string& str) {cout << str << " :"; });
//for_each(a.cbegin()->second.cbegin(), a.cbegin()->second.cend(), [](const size_t& num) {cout << num << " "; });
删除元素,接受一个key_type,即关键字,删除关键字匹配的所有元素。
对于map和set:由于他们必须是不重复的关键字,所以erase的结果要么为0,要么为1。0表示删除的元素不存在
对于multimap和multiset:他们接受重复关键字,所以erase的结果可以是大于1,表示删除的个数。
multimap<string, int> a{ {"wo",1},{"ar",2},{"wo",2} };
cout<<a.erase("wo"); //结果为2
同时erase也接受迭代器的指定的范围删除。
下标运算符和at函数。
set类型不支持下标;multimap和unordered_multimap不能进行下标操作(可以会有多个值对应关键字)。
对map执行下标操作: 如果关键字在map中,会找到对应的值;如果不在map中,会创建一个元素,默认值为0
map<string, int> a;
cout << a["wda"] << endl; //使用默认的字-值对:wda - 0
at访问,如果关键字不存在,则会报错。
对map进行下标操作,会获得一个mapped_type;对map进行解引用,会获得一个value_type。
map的下标操作返回一个左值,既可以读也可以写。
find和count:find查找元素出现的位置,没找到则返回尾后迭代器;count返回元素出现的次数。
下标操作如果关键字不在map中,则会创建一个默认的字-值对;但我们不希望改变map的结构。
find没有找到会返回 end。
map<string, int> a{ {"wo",1},{"ao",2},{"po",3} };
if (a.find("ylh") == a.end())
{
cout << "没有找到!\n";
}
multimap<string, int> a{ {"ylh",666},{"ylh",999},{"ylh",888},{"asd",555} };
auto a_count = a.count("ylh"); //查找出指定字出现的次数
auto it_beg = a.find("ylh"); //查找第一个出现的位置
while (a_count)
{
cout << it_beg->second << " "; //打印目标
++it_beg; //递增到下一目标
--a_count; //计数递减
}
lower_bound:返回的迭代器指向第一个具有给定关键字的元素。
upper_bound:返回的迭代器指向最后一个匹配元素之后的位置
multimap<string, int> a{ {"ylh",666},{"ylh",999},{"ylh",888},{"asd",555},{"zdwa",555},{"zoef",565} };
// beg指向第一个符合条件的元素,end指向最后一个符合条件的元素的下一个位置
for (auto beg = a.lower_bound("ylh"), end = a.upper_bound("ylh"); beg != end; ++beg)
{
cout << beg->second << endl;
}
ps:他们的返回值可以作为一个迭代器范围。
如果没有元素与给定关键字匹配,则lower_bound和upper_bound返回相等位置的迭代器。
接受一个关键字,返回一个迭代器pair。
beg为a第一个出现关键字的位置的一个迭代器pair:
pair的first成员为找到的第一个位置的迭代器,second成员为找到的最后一个符合关键字的下一个位置迭代器。
pair<multimap<string,int>::iterator,multimap<string,int>::iterator>
其实就是lower_bound和upper_bound的简写版:
multimap<string, int> a{ {"ylh",666},{"ylh",999},{"ylh",888},{"asd",555},{"zdwa",555},{"zoef",565} };
for (auto beg=a.equal_range("ylh");beg.first!=beg.second;++beg.first)
{
cout << beg.first->second << endl;
}
beg的first为找到的第一个符合条件的迭代器,他是一个pair类型对象,解引用或者->运算符得到pair的first或者second。
在multimap
multimap<string, string> a{ {"ylh","iot"} ,{"wad","dwapd"},{"ylh","posa"},{"ylh","zbcd"},{"xsd","podv"}};
auto fin_it = a.find("ylh"); //查找关键字出现的位置
auto count = a.count("ylh"); //统计关键字出现的次数
while (count)
{
if (fin_it->second == "zbcd") //如果找到了值为zbcd的元素位置
{
a.erase(fin_it); //删除元素
break;
}
++fin_it;
--count;
}
for (auto beg = a.cbegin(); beg != a.cend(); ++beg)
{
cout << beg->first << ": " << beg->second << endl;
}
删除指定的所有关键字和值:
multimap<string, string> a{ {"ylh","iot"} ,{"wad","dwapd"},{"ylh","posa"},{"ylh","zbcd"},{"xsd","podv"}};
auto beg = a.equal_range("ylh"); //找到关键字的位置
a.erase(beg.first,beg.second); //删除全部此关键字
无序容器不使用比较运算符来组织元素,而是使用一个哈希函数,和关键字的==运算符。
使用无序容器来统计单词,但是不会以字典序的形式输出
unordered_map<string, size_t> word_count;
string word;
while (cin >> word)
{
++word_count.insert({ word,0 }).first->second;
}
for (const auto& x : word_count)
{
cout << x.first << " occurs " << x.second << ((x.second > 1) ? " times" : " time") << endl;
}
无序容器的桶操作