周末一晃就过,Ok,那就让我们继续我们的新内容吧,在上一讲,我们主要说map的下标操作和pair结构,同
时我们用一个例子来说明了map下标的实用,那么当我们需要添加学生成绩时,我们该怎么做呢?当然大家可能会
说,先把成绩储存进map<string,double>里面,然后再调用AddStudent不就可以了吗?当然这样做是没错的了,但是我们学了这么久的C++,难道就只能弄出个这玩意吗?C++最为显著的特点就是用类来表示概念,所以这一切操作我们都可以将他放进Students里面:
——————————-
class Students{
public:
/////
// ///
void AddScore(const string&
name,
const string&
course,
const double&
score);
////
// ////
};
void Students::AddScore(const string&
name,
const string&
course,
const double&
score){
_name[name].insert(make_pair(course,score));
}
——————————
如此一来,我们便可以这样使用:
—————————–
Students s;
map<string,double>m;
m["
Math"
] = 60;
m["
English"
] = 70;
m["
Chinese"
] = 80;
s.AddStudent("
ZhangSan"
,m);
s.AddStudent("
LiSi"
,m);
s.AddStudent("
WangEr"
,m);
cout<<"
====================="
<<endl;
s.ShowScore("
ZhangSan"
);
//打印ZhangSan成绩单
cout<<"
====================="
<<endl;
s.AddScore("
ZhangSan"
,"
Physics"
,78.5);
//为ZhangSan添加一门课程信息
ShowStudentsInfo(s);
//打印所有学生的信息
——————————-
Ok,这样一来,这个学生成绩的class算是差不多完成了,当然我们可以根据实际的需要再添加些信息,比如说,我们一开始就知道有哪些课程,我们可以把这些课程封装起来……好像扯得有些远了,这貌似不是我们现在说的主题。好吧,继续把头拉回来,我们来纵观一下这个学生成绩类,这个类几乎就是全靠map数据结构堆叠起来的,使用map,可以极大程度地减轻了我们的负担。就比如说上面的AddScore,如果我们不适用map的话,可能会绕些弯子,但是我们使用map的话,就一句话的事儿。insert是map里的一个操作方式,我们接下来会说,make_pair我们已经说过了,这个函数很有用,这不就见识到他的妙用了吗?
可能大家注意到一个现象了,就是我们打印出来的信息的顺序似乎和我们一开始所以为的有些区别,无论我们的插入顺序是什么,但打印顺序始终没变,这是为什么呢?今天,我们就来把这问题弄清楚,看是咋回事:
——————————
template<typename Key,typename T,typename Cmp=less<Key>,
typename A=allocator<pair<const Key,T
>>>
class map{
public:
/////
// ///
explicit map(const Cmp&
=Cmp(),const A&
=A());
//默认情况下,我们使用的是<操作符来比较的。
template<typename U>
map(U first,U last,const Cmp&
=Cmp(),const A&
=A());
//这里只有U是输入迭代器才能够通过。
map(const map&
);
typedef Cmp key_compare;
class value_compare:public binary_function<value_type,value_type,bool>{
friend class map;
//关于binary_function我们以后会说,这里大家只需要知道他是函数对象的一个基类就可以。
protected:
Cmp cmp;
value_compare(Cmp c):cmp(c){ }
public:
bool operator()(const value_type&
x,const value_type&
y) const{
return cmp(x.first,y.first);
}
};
key_compare key_comp() const;
value_compare value_comp() const;
// ///
};
—————————————-
从构造函数中,我们可以看出,Cmp已经给了默认值,所以,通常在我们不明确指出需要什么比较方式map会使用默认的小于操作符来做比较,所以,我们看到是一个字典序。
除了默认情况的用法,我们可以这样使用map:
————————————–
class Nocase:public binary_function<string,string,bool>{
public:
bool operator()(const string&
_str,const string&
str){
string::const_iterator it = _str.begin();
string::const_iterator _it = str.begin();
while (it != _str.end() &
&
_it != str.end()){
if (toupper(*it) != toupper(*_it))
return toupper(*it) <toupper(*_it) ? true : false;
++it;
++_it;
}
return _str.length() == str.length() ? false : _str.length() <str.length() ? true : false;
}
};
//这是一个函数对象,意思就是不区分大小写的对比,注意上面的三元操作符的嵌套使用。
int main(){
map<string, double>_m;
_m["
Math"
] = 80;
_m["
English"
] = 92;
_m["
Chinese"
] = 85;
_m["
abc"
] = 86;
map<string, double>::iterator _it = _m.begin();
while (_it != _m.end()){
cout <<_it->
first <<"
t"
<<_it->second <<endl;
_it++;
}
cout <<"
—————-华丽的分割线————-n"
;
map<string, double,Nocase>m;
m["
Math"
] = 80;
m["
English"
] = 92;
m["
Chinese"
] = 85;
m["
abc"
] = 86;
map<string, double,Nocase>::iterator it = m.begin();
while (it != m.end()){
cout <<it->
first <<"
t"
<<it->second <<endl;
it++;
}
return 0;
}
———————————————
当我们把我们自定义的一个比较器Nocase传递给map时,map里面的的函数对象value_compare()调用的就是Nocase(),也就是我们上面的函数对象。
好吧,现在已不早,今天就到这里吧,有什么不懂的直接提问。
=========================
回复D直接查看目录。
原文始发于微信公众号(
C/C++的编程教室
):第七十八讲 细说map(4)
|