)关联容器

Posted 简约AI

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了)关联容器相关的知识,希望对你有一定的参考价值。

笔记较为零散,都是自己不熟悉的知识点。

习题答案至于一个.cc 中,包含Chapter7.h头文件,读入文件包括./test ./rules .需要演示某一题直接修改 #define NUM****, 如运行11.23题为#define NUM1123;

chapter 11

1.  关联容器不支持顺序容器的位置相关的操作,例如push_front或push_back。原因是关联容器中元素是根据关键字存储的,这些操作对

关联容器没有意义。而且关联容器也不支持构造函数或插入操作这些接收一个元素值和一个数量值的操作。

其中,关联容器的迭代器都是双向的。

传递给平【排序算法的可调用对象必须满足与关联容器中关键字一样的类型要求。

2.  为了使用自己定义的操作,在定义multiset时我们必须提供两个类型:关键字类型Sales_data,以及比较操作类型--应该是一种函数指针

类型,指向comparaIsbn.

multiset<Sales_data,decltype(compareIsbn)* >     //使用decltype来指出自定义操作的类型。

       bookstore(compareIsbn);

当用decltype来获得一个函数指针类型时,必须加上一个*来指出我们要使用一个给定函数类型的指针。

3. 与其他标准库类型不同,pair的数据成员是public的。两个成员分别是first和second。

对于set类型,key_type和value_type是一样的,set中保存的就是关键字。map中元素是关键字-值对,即每个元素是一个pair对象,

包含一个关键字和一个关联的值。由于不能改变一个元素的关键字,因此这些pair的关键字部分是const:

与顺序容器一样使用作用域运算符来提取一个类型的成员: map<string,int>::key_type .

只有map类型(unordered_map,unordered_multimap,map)才定义了mapped_type。

要记住,一个map的value_type是一个pair,我们可以改变pair的值,但不能改变关键字成员的值。

4.  由于map和set(以及对应的无序元素)包括不重复的关键字,因此插入一个已存在的元素对容器没有任何影响、

auto ret =word_count.insert({word, 1});

ret保存insert返回的值,是一个pair;  ret.first是pair的第一个成员,是一个map的迭代器,指向具有给定关键字的元素。

ret.first -> 解引用此迭代器,提取map中的元素,元素也是一个pair。

5.  一个给定的关键字只能出现一次。这样任意给定的单词只有一个关联的计数器。而在mutil容器的关键字不必唯一。

erase操作与对应的顺序容器的操作非常相似:指定的元素被删除,函数返回void。

对一个map使用下标操作,其行为与数组或vector上的下标操作很不相同: 使用一个不在容器中的关键字作为下标,会添加一个具有此

关键字的元素到map中。

map的下标运算符与我们用过的其他下标运算符的另一个不同是返回类型。通常,解引用一个迭代器与下标运算符返回的类型是一样的。

但对map则不然:当对一个map进行下标操作时,会获得一个mapped_type对象,当解引用一个map迭代器时,会得到一个value_type对象。

map下标返回一个左值,所以我们既可以读也可以写元素。

6.  set<int> iset = {0,1,2,3,4,5};

       iset.find(11);   //当11超过iset大小时,返回的迭代器,其值等于iset.end()

lower_bound 和upper_bound不适用于无序容器,下标和at操作只适用于非const的map和unorderd_map。

如果一个multimap或multiset中有多个元素具有给定关键字,则这些元素在容器中会相邻存储。

c.equal_range(k);  返回一个迭代器pair,表示关键字等于k的元素的范围,若k不存在,pair的两个成员均等于c.end()。

7. lower_bound返回的迭代器可能指向一个具有给定关键字的元素,但也可能不指向。如果关键字不再容器中,则lower_bound

会返回关键字的第一个安全插入点--不影响容器中元素的插入位置。

无序关联容器不是使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。在关键字类型的元素没有明显的序关系的

情况下,无序容器是非常有用的。unordered_map/ordered_set。

brb be right back
k okay?
y why
r are
u you
pic picture
thk thanks!
l8r later
where r u
y dont u send me a pic 
k thk l8r

//Chapter7.h
#ifndef CHAPTER7_H
#define CHAPTER7_H

#include <iostream>
#include <vector>
using namespace std;

class Sales_data;
istream &read(istream &is, Sales_data &item);
class Sales_data {
	friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
	friend istream &read(istream &is, Sales_data &item);
	friend ostream &print(ostream &os, const Sales_data &item);

public:
//	Sales_data(){};
	Sales_data(const string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p){ 
		cout <<"Sales_data(const string &, unsigned, double)" << endl;
	}
	Sales_data(){
		cout << "Sales_data()" << endl;
	}
/*	Sales_data() : Sales_data("", 0, 0.0f){
		cout << "Sales_data()" << endl;
	}
*/	Sales_data(const string &s):bookNo(s), units_sold(0), revenue(0.0){ 
		cout << "Sales_data(const string& s)"<<endl;
	}
	Sales_data(istream &is){ 
		cout << "Sales_data(istream &)" <<endl;
		read(is, *this);
	}
	string isbn() const{ return bookNo; }
	Sales_data& combine(const Sales_data&);
private:
	inline double avg_prive() const;

	string bookNo;
	unsigned units_sold;
	double revenue;
};
Sales_data& Sales_data::combine(const Sales_data& rhs){
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}

double Sales_data::avg_prive() const{
	return units_sold ? revenue / units_sold : 0;
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs){
	Sales_data sum = lhs;
	sum.combine(rhs);
	return sum;
} 
istream &read(istream &is, Sales_data &item){
	double price(0.0);
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = price * item.units_sold;
	return is;
}
ostream &print(ostream &os, const Sales_data &item){
	os << item.isbn() << " " << item.units_sold << " " <<item.revenue;
	return os;
}
//class person
class Person;
istream &read(istream &is, Person &item);
class Person{
	friend istream &read(istream &is, Person &item);
	friend ostream &print(ostream &os, const Person &item);
public:
	Person(){};
	Person(const string &n, const string &addr): name(n), address(addr){ }
	Person(istream &is){ read(is, *this); }
private:
	string name;
	string address;
	string getName() const { return name; }
	string getAddress()const  { return address; }
};
istream &read(istream &is, Person &p){
	is >> p.name >> p.address;
	if(!is) 
		p = Person();
	return is;
}
ostream &print(ostream &os, const Person &p){
	os << p.getName() << p.getAddress();
	return os;
}
//class Screen
class Screen;
class Window_mgr{
	public:
		typedef vector<Screen>::size_type ScreenIndex;
		inline void clear(ScreenIndex);
	private:
		vector<Screen> screens;
};

class Screen{
	friend void Window_mgr::clear(ScreenIndex);
public:
	typedef string::size_type pos;
	Screen(){}
	Screen(pos ht, pos wd): height(ht), width(wd), contents(ht * wd, ' ') { }
	Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c){}
	
	char get(){	return contents[cursor]; }
	char get(pos r, pos c) const { return contents[r * width + c]; }
	inline Screen &set(char c);
	inline Screen &set(pos r, pos c, char ch);
	inline Screen &move(pos r, pos c);
	const Screen &display(ostream &os) const{
		os << contents;
		return *this;
	}
	pos size() const;
private:
	pos cursor;
	pos height, width;
	string contents;

};

Screen::pos Screen::size() const{
	return height * width;
}

inline Screen &Screen::set(char c){
	contents[cursor] = c;
	return *this;
}

inline Screen &Screen::set(pos r, pos col, char ch){
	contents[r * width + col] = ch;
	return *this;
}

inline Screen &Screen::move(pos r, pos c){
	pos row = r * width + c;
	cursor = row + c;
	return *this;
}
//class Account
class Account{
public:
	Account(){}
	Account(string &s, double m): owner(s), amount(m){}
	void calculate(){ amount += amount * interestRate; }
	static double rate() { return interestRate; }
	static void rate(double newrate){ interestRate = newrate;}
private:
	string owner;
	double amount;
	static double interestRate;
	static constexpr double todayRate = 3.65;
	static double initRate(){ return todayRate; }
};

#endif
//main.cc
#include <fstream>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <cctype>
#include <map>
#include <vector>
#include <list>
#include <utility>
#include <set>
#include <unordered_map>
#include "Chapter7.h"
using namespace std;
#define NUM1138

/*11.11*/
bool compareIsbn(Sales_data& lhs, Sales_data& rhs){
	return lhs.isbn() < rhs.isbn();
}
/*11.33*/
map<string, string> buildmap(ifstream& map_file){
	map<string, string> trans_map;
	for(string key, value; map_file >> key && getline(map_file, value); )
		if(value.size() > 1)
			trans_map[key] = value.substr(1);
		//	trans_map.insert({key, value.substr(1)});
	return trans_map;
}

const string& transform(const string &s, const map<string, string> &m){
/*11.34*/
//	auto key = m[s];
	auto map_it = m.find(s);
	if(map_it != m.end())
		return map_it -> second; // map_it 是const_interator类型,返回值类型加const
	else 
		return s;
}
void word_transform(ifstream &map_file, ifstream& input){
	auto trans_map = buildmap(map_file);
	cout << "transformation: "<<endl;
	for(auto entry = trans_map.begin(); entry != trans_map.end(); ++entry){
		cout <<"key: " << entry->first << " " <<" value: "<< entry-> second << endl;
	}
	cout << "\n\n";
	for(string text; getline(input, text); ){
		istringstream iss(text);
		for(string word; iss >> word; ){
			cout << transform(word, trans_map) <<" ";
		}
		cout << endl;
	}
}
/*11.38*/
void word_transform(){
	ifstream ifs_map("./rules"), ifs_content("./test");
	if(ifs_map && ifs_content){
		unordered_map<string, string> trans_map;
		for(string key, value; ifs_map >> key && getline(ifs_map, value); )
			if(value.size() > 1)
				trans_map[key] = value.substr(1);
		for(string text, word; getline(ifs_content, text); cout <<endl)
			for(istringstream iss(text); iss >> word; ){
				auto map_it = trans_map.find(word);
				cout << (map_it == trans_map.end() ? word : map_it->second)<< " ";
			}
	}
	else 
		cerr << "Can't find the documents. "<<endl;

}

int main(){
/*11.1*/
#ifdef NUM111
	cout << "map是关键字和值的集合,我们通过关键字来保存和访问. "
			"vector是对象的集合,按照它们在容器中的位置来顺序保存和访问. "<<endl;
#endif
/*11.2*/
#ifdef NUM112
	cout << "list 相同的数据结构需要在各处插入和删除的情况, 如成绩 ;"
			"vector 适合下标频繁访问的同类型数据 ;"
			"deque消息队,先入先出; "
			"map 字典 ; set: bad_checks. " <<endl;
#endif
/*11.3*/
#ifdef NUM113
	map<string, size_t> word_cout;
	string word;
	while(cin >> word)
		++word_cout[word];
	for(auto &it : word_cout)
		cout << it.first << " occurs "<< it.second 
			<< ((it.second >1) ? " times" : " time" )<<endl;//需要括号
#endif
/*11.4*/
#ifdef NUM114
	map<string, size_t> word_cout;
	string word;
	while(cin >> word){
		for(auto & w : word)
			w = tolower(w);
			word.erase(remove_if(word.begin(), word.end(),::ispunct), word.end());
			++word_cout[word];   //ispunct为全局作用域函数
	}
	for(auto &it : word_cout)
		cout << it.first << " occurs "<< it.second 
			<< ((it.second >1) ? " times" : " time" )<<endl;//需要括号
#endif
/*11.5*/
#ifdef NUM115
	cout<< "set就是元素类型都是关键字类型, map是关键字-值对的集合,两者合成一个项目元素. 如果只用到关键字就用set,当用到关键字-值对时用map. "<<endl;
#endif
/*11.6*/
#ifdef NUM116
	cout<< "list的元素有序并且是重复的,set中的元素无序且是不重复的. "<<endl;
#endif
/*11.7*/
#ifdef NUM117
	map<string, vector<string> > family;
	string lastName, firstName;
	for(cout << "Please input last name: "; cin >> lastName && lastName != "exit";){
		for(cout << "Please input first name: "; cin >> firstName && firstName != "exit";)
			family[lastName].push_back(firstName);
		cout << "Please input last name: "<<endl;
	}
	for(auto &it : family){
		cout << it.first;
		for(auto &iter : it.second)
			cout << " " << iter;
		cout <<endl;
	}
#endif
/*11.8*/
#ifdef NUM118
	vector<string> vec;
	string word;
	while(cin >> word){
		if(find(vec.begin(), vec.end(), word) != vec.end())
			cout << "excluded !" <<endl;
		else
			vec.push_back(word);
	} 
	for(auto const& s : vec)	cout << s << " ";
	cout << endl;
	unique_copy(vec.begin(), vec.end(), ostream_iterator<string>(cout, " "));
	cout << endl;
#endif
/*11.9*/
#ifdef NUM119
    map<string, list<size_t>> word_row;
#endif
/*11.10*/
#ifdef NUM1110
	cout << "可以定义." << endl;

	vector<int> vec;
	list<int> lst;
	map<vector<int>::iterator, int > m1;
	map<list<int>::iterator, int> m2;	

	m1.insert(pair<vector<int>::iterator, int>(vec.begin(), 0);
	m2.insert(pair<vector<int>::iterator, int>(lst.begin(), 0);
#endif
/*11.11*/
#ifdef NUM1111
	typedef bool(*)(const Sales_date &lhs, const Sales_date &rhs) compareType;
	multiset<Sales_date, compareType) bookstore(compareIsbn);	
#endif
/*11.12*/
#ifdef NUM1112
	vector<pair<string, int> > vec;
	string str;
	int i; 
	while(cin >> str >> i)
		vec.push_back(pair<string, int>(str, i));
	for(auto &p : vec)
		cout << p.first << " "<< p.second <<endl;
#endif
/*11.13*/
#ifdef NUM1113
	vector<pair<string, int> > vec;
	string str; 
	int i;	
	vec.push_back(pair<string, int>(str, i));
	vec.push_back(make_pair(str, i));
	vec.push_back({str, i});
	vec.emplace_back(str, i);  //最简单
#endif
/*11.14*/
#ifdef NUM1114
class Families {
public:
    using Child = pair<string, string>;
    using Children = vector<Child>;
    using Data = map<string, Children>;

    void add(string const& last_name, string const& first_name, string birthday)
    {
        _data[last_name].push_back(make_pair(first_name, birthday));
    }

    ostream& print(ostream& os) const
    {
        if (_data.empty()) return os << "No data right now." << endl;

        for (const auto& pair : _data) {
            os << pair.first << ":\n";
            for (const auto& child : pair.second)
                os << child.first << " " << child.second << endl;
            os << endl;
        }
        return os;
    }

private:
    Data _data;
};

	Families families;
    string message = "Please enter last name, first name and birthday";
    for (string l, f, b; cout << message << endl, cin >> l >> f >> b;
         families.add(l, f, b))
        ;
    families.print(cout << "Families data:" << endl);

#endif
/*11.15*/
#ifdef NUM1115
	cout <<"mapped_type是vector类型, key_type是int值类型, value_type是pair类型."<<endl;
#endif
/*11.16*/
#ifdef NUM1116
	map<string, int> m;
	m["linux"] = 25;
	map<string, int>::iterator it = m.begin();
	it -> second = 50;
#endif
/*11.17*/
#ifdef NUM1117
	cout << "第二句是非法的,因为set类型并没有push_back的用法. " <<endl;
#endif
/*11.18*/
#ifdef NUM1118
	map<string, int> word_count;
	map<string, int>::const_iterator map_it = word_count.begin();
	while(map_it != word_count.end()){
		cout << map_it->first << " occurs" <<map_it->second <<" times"<<endl;
		++map_it;
	}
#endif
/*11.19*/
#ifdef NUM1119
	using compareType = bool (*)(const Sales_data &lhs, const Sales_data &rhs);
	multiset<Sales_data, compareType>bookstore(compareIsbn);
	multiset<Sales_data, compareType>::iterator c_it = bookstore.begin();

#endif
/*11.20*/
#ifdef NUM1120
	
    map<string, size_t> word_count;
    string word;
    while (cin >> word) {
        auto ret = word_count.insert({word, 1});
        if (!ret.second) ++ret.first->second;
    }
    for (const auto& w : word_count)
        cout << w.first << " " << w.second
                  << ((w.second > 1) ? " times" : " time") << endl;
	cout << "insert插入更容易编写和阅读." << endl;
#endif
/*11.21*/
#ifdef NUM1121
	cout << "对map中pair的size_t类型递增的操作. "<<endl;
#endif
/*11.22*/
#ifdef NUM1122
	cout << "参数类型: <string, vector<int> > "
			"返回类型: pair<map<string, vector<int>::iterator, bool>"<<endl;
#endif
/*11.23*/
#ifdef NUM1123
	multimap<string, string> families;
	string lastName; string firstName;
	for(; cin >> firstName >> lastName; 
						families.insert({lastName, firstName})) //or insert(make(lastName, firstName))
		;
	for(auto &i : families)
		cout << i.second << " "<< i.second <<endl;
#endif
/*11.24*/
#ifdef NUM1124
 	map<int, int> m;
	m[0] = 1;
	for (const auto& e : m) std::cout << e.first << " " << e.second << "\n";
	cout << "赋值操作. "<<endl;
#endif
/*11.25*/
#ifdef NUM1125
    vector<int> v;
    v[0] = 1;
	cout <<"vec: "<<endl;
    for (const auto& e : v) std::cout << e << "\n";
#endif
/*11.26*/
#ifdef NUM1126
    map<int, string> m = {{1, "linux"}, {2, "c++"}};

    map<int, string>::key_type type_to_subscript = 1;

    map<int, string>::mapped_type type_to_return =  map[type_to_subscript];
#endif
/*11.27*/
#ifdef NUM1127
	cout << "对于允许存在重复元素的multimap和multiset用count,对于只有unique元素的map用find."<<endl;
#endif
/*11.28*/
#ifdef NUM1128
 	map<string, std::vector<int>> m;
    m = {{"Alan", {1, 2, 3, 4, 5, }},
         {"John", {1, 5, 6, 7, 8}}};
    map<string, vector<int>>::iterator it;
    // type used to define this iterator.
 	it = m.find("Alan");
	cout << it -> second[2] <<endl;
#endif
/*11.29*/
#ifdef NUM1129
	cout << "upper bound返回指向关键字的插入点.lower bound返回关键字的第一个插入点,不影响容器中顺序的插入位置. equal_range 返回一个迭代器pair,两个迭代器都指向关键字可以插入的位置. "<<endl;
#endif
/*11.30*/
#ifdef NUM1130
	cout << "pos为一个迭代器pair,pos.first迭代器指向匹配关键字的第一个元素, "
			"pos.first->second指向匹配关键字的value部分. " << endll;
#endif
/*11.31*/
#ifdef NUM1131
	multimap<string, string> mm{ {"cc","dd"}, {"gg","hh"}, {"aa", "bb"},{"cc","dd1"}};
	for(auto &i : mm)
		cout << i.first <<" "<< i.second << endl;
	string author = "cc";
	string word = "dd";
	auto found = mm.find(author);
	mm.erase(found);
	cout << "*******This is apart line******"<<endl;;
	for(auto &i : mm)
		cout << i.first <<" "<< i.second << endl;
#endif
/*11.32*/
#ifdef NUM1132
	multimap<string, string> mm{ {"cc","dd"}, {"gg","hh"}, {"aa", "bb"},{"cc","dd1"}};
	
	map<string, multiset<string>> order_mm;
	for(auto & author : mm)
		order_mm[author.first].insert(author.second);
	
	for(auto &author : order_mm){
		cout << author.first << ": ";
		for(auto &work : author.second)
			cout << work << " ";
	cout << endl;
	}
#endif
/*11.33*/
#ifdef NUM1133
    ifstream ifs_map("./rules"),
        ifs_content("./test");
    if (ifs_map && ifs_content)
        word_transform(ifs_map, ifs_content);
    else
        std::cerr << "can't find the documents." << std::endl;
#endif
/*11.34*/
#ifdef NUM1134
	cout << "在上一题中修改演示报错, 因为map的迭代器并没有声明为const类型,但是m被声明为const的map类型,如果插入新的pair元素,就会出错. "<<endl;
#endif
/*11.35*/
#ifdef NUM1135
	cout << "效果没有差别,但是使用下标运算符,如果关键字存在多次,将只保存最后出现的元素。"
			"如果使用insert,当关键字存在对此时,则会将第一次出现的关键字保存在map中. "<<endl;
#endif
/*11.37*/
#ifdef NUM1137
	cout << "无序容器:在一个关键字类型没有明显的顺序关系容器时有优势,有时维护有序容器的成本很高,这时也可以用无序容器."
			"有序容器:可以通过关键字的迭代器访问有序容器." <<endl;
#endif
/*11.38*/
#ifdef NUM1138
//word_count
	unordered_map<string, int> word_count;
	for(string word; cin >> word; ++word_count[word])
		;
	for(auto &i : word_count)
		cout << i.first << " occurs: " << i.second 			<< (i.second > 1 ? " times" : "time" )<<endl;

//word_transform
word_transform();
#endif
	return 0;
}

参考资料:

c++ primer中文版第五版,电子工业出版社。

c++ primer第四版习题解答,人民邮电出版社。

[email protected]://github.com/pezy/CppPrimer




以上是关于)关联容器的主要内容,如果未能解决你的问题,请参考以下文章

)关联容器

HackingC++ Learning笔记 Chapter5-Standard Library – Part 1

零元学Expression Blend 4 - Chapter 12 用实例了解布局容器系列-「Viewbox」

零元学Expression Blend 4 - Chapter 10 用实例了解布局容器系列-「StackPanel」

零元学Expression Blend 4 - Chapter 8 用实例了解布局容器系列-「Grid」

零元学Expression Blend 4 - Chapter 11 用实例了解布局容器系列-「Border」