一、标准模板库(STL)
(p.s. STL中的常用实用工具
auto_ptr
string
pair
)
1.定义了一系列的容器模板(类模板),实现泛型化的数据结构。
1)向量(vector, 这里说的"向量"就是数组), 向量内存连续,支持下标访问和随机迭代,只有在尾部进行插入和删除效率才比较高。
2)列表(list),内存不连续,不支持下标访问和随机迭代,在任何位置进行插入和删除效率都很高。
3)双端队列(deque),内存连续,支持下标访问和随机迭代,在首尾两端进行插入和删除效率都比较高。
以上三种合称为线性容器。
4)堆栈(stack),后进先出
5)队列(queue),先进先出
6)优先队列(priority_queue),优者先出
以上三种合称为适配器容器,通过某种线性容器适配。
7)映射(map),是键值对(KVP)的集合,按键升序,键唯一。 采用了有序二叉树(二叉搜索树)数据结构实现。
8)集合(set),没有值只有键的映射, 按键升序。
9)多重映射(multimap),允许重复键的映射,即键不唯一。按键升序。
10)多重集合(multiset),没有值只有键的多重映射。按键升序。
以上四种合称为关联容器。通过有序树表达数据的关联性。按键升序。
2.泛型函数(函数模板)
template<typename T>
void swap (T& a, T& b) {
T c = a;
a = b;
b = c;
}
template<typename IT>
void print (IT begin, IT end) {
while (begin != end)
cout << *begin++ << ‘ ‘;
cout << endl;
}
int a[5] = {1, 2, 3, 4, 5};
print (a, a + 5);
List list;
list.push_back (...);
...
print (list.begin (), list.end ());
1 /* 2 * STL函数for_each练习 3 * 4 * */ 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 /* 9 template<typename IT, typename DOIT> 10 void for_each (IT begin, IT end, DOIT doit) { 11 while (begin != end) 12 doit (*begin++); 13 } 14 */ 15 void print (int& x) { 16 cout << x << endl; 17 } 18 void add (int& x) { 19 ++x; 20 } 21 int main (void) { 22 int a[5] = {1, 2, 3, 4, 5}; 23 for_each (a, a + 5, print); 24 for_each (a, a + 5, add); 25 for_each (a, a + 5, print); 26 return 0; 27 }
二、STL容器共性
1.所有的容器都支持拷贝构造和拷贝赋值,可以完整意义上的容器对象副本。
2.所有的容器都支持“==”运算符。
(p.s.容器的相等:容器的类型相同,容器中元素的类型相同,容器中元素的个数相等,对应元素还要满足相等性的判断)
3.容器中元素都是放入了源对象拷贝,而非源对象本身。
int b;
int a[3];
a[0] = b;
a[0]++;
4.容器中元素需要支持完整的拷贝语义。
(p.s. auto_ptr不适合放在容器中使用, 因为auto_ptr中为了防止double free把拷贝构造作成了是一种传递拷贝,不是真正意义上的拷贝)
5.如果需要对容器的元素进行排序或者查找操作,该元素的类型还需要支持“<”和“==”操作符。
三、向量(vector)
1.基本特点
1)连续内存和下标访问
2)动态内存管理
int a[10];
int *b = new int[10];
3)通过预分配内存空间减小动态内存管理的额外开销
4)可以再随机位置做插入和删除,但只有在接近尾部的操作才是高效的。
2.定义变量
#include <vector>
using namespace std;
vector<int> vi;
vector<string> vs;
3.迭代器
vector<...>::iterator - 正向迭代器
vector<...>::const_iterator - 常正向迭代器
vector<...>::reverse_iterator - 反向迭代器
vector<...>::const_reverse_iterator - 常反向迭代器
向量的四种迭代器都是随机迭代器,可以和整数做加减运算。
通过vector<...>调用,begin()返回起始迭代器,end()返回终止迭代器,最后一个元素的下一个位置。rbegin()返回起始反向迭代器,rend()返回终止反向迭代器。
通过const vector<...>&/*调用以上函数,返回的将是const_iterator/const_reverse_interator。
注意:任何容器,在结构性修改之前获得的迭代器,有可能因为这种修改而失效,或者不能标识正确的位置,这时候如果要继续使用迭代器,最好重新初始化迭代器。
4.预分配和初始化
vector<int> vi (10);
将vi初始化10个int元素,初始值为0。
vector<类> vc (10);
将vi初始化10个类类型的元素,通过无参构造函数初始化。
vector<int> vi (10, 8);
将vi初始化10个int元素,初始值为8。
vector<类> vc (10, 类 (...));
将vi初始化10个类类型的元素,通过拷贝构造函数初始化。
1 /* 2 *vector举例 3 */ 4 #include <iostream> 5 #include <vector> 6 using namespace std; 7 class A { 8 public: 9 A (int i = 0) : m_i (i) {}; 10 int m_i; 11 }; 12 void print (const vector<int>& vi) { 13 size_t size = vi.size (); 14 cout << size << endl; 15 for (size_t i = 0; i < size; ++i) 16 cout << vi[i] << ‘ ‘; 17 cout << endl; 18 } 19 int main (void) { 20 vector<int> vi; 21 vi.push_back (10); 22 vi.push_back (20); 23 vi.push_back (30); 24 vi.push_back (20); 25 vi.push_back (10); 26 print (vi); 27 vi.pop_back (); 28 print (vi); 29 ++vi.front (); 30 vi.back () = 100; 31 cout << vi.front () << ‘ ‘ << vi.back () << endl; 32 typedef vector<int>::iterator IT; 33 typedef vector<int>::const_iterator CIT; 34 typedef vector<int>::reverse_iterator RIT; 35 typedef vector<int>::const_reverse_iterator CRIT; 36 for (IT it = vi.begin (); it != vi.end (); ++it) 37 ++*it; 38 const vector<int>& cvi = vi; 39 for (CIT it = cvi.begin (); it != cvi.end (); ++it) 40 cout << /*--*/*it << ‘ ‘; 41 cout << endl; 42 for (CRIT it = cvi.rbegin (); it!=cvi.rend(); ++it) 43 cout << *it << ‘ ‘; 44 cout << endl; 45 vector<string> vs; 46 vs.push_back ("beijing"); 47 vs.push_back ("tianjin"); 48 vs.push_back ("shanghai"); 49 cout << *(vs.begin () + 2) << endl; 50 *const_cast<char*> ((vs.end () - 1)->c_str ())=‘S‘; 51 cout << *(vs.end () - 1) << endl; 52 vector<int> vi2 (10); 53 print (vi2); 54 vector<A> va (10); 55 for (vector<A>::const_iterator it = va.begin (); 56 it != va.end (); ++it) 57 cout << it->m_i << ‘ ‘; 58 cout << endl; 59 vector<int> vi3 (10, 8); 60 print (vi3); 61 vector<A> va2 (10, A (8)); 62 for (vector<A>::const_iterator it = va2.begin (); 63 it != va2.end (); ++it) 64 cout << it->m_i << ‘ ‘; 65 cout << endl; 66 return 0; 67 }
5.size()/resize()/clear()/capacity()/reserve()
size() - 获取元素个数,而不是容量。
resize() - 增减元素的个数,增引发构造,减引发析构。如果在新增元素时发现当前容量不够,自动扩容。但是在减少元素时不会自动收缩容量。
clear() - 清空所有的元素,导致析构。同样不会自动收缩容量。
capacity() - 获取容量,以元素为单位。
reserve() - 手动扩容。新增部分不做初始化。
1 /* 2 *size() capacity()练习 3 */ 4 #include <iostream> 5 #include <vector> 6 using namespace std; 7 void print (const vector<int>& vi) { 8 cout << "大小:" << vi.size () << endl; 9 cout << "容量:" << vi.capacity () << endl; 10 for (vector<int>::const_iterator it = vi.begin (); 11 it != vi.end (); ++it) 12 cout << *it << ‘ ‘; 13 cout << endl; 14 } 15 int main (void) { 16 vector<int> vi (5, 3); 17 print (vi); 18 vi.push_back (4); 19 print (vi); 20 vi[6] = 100; 21 cout << vi[6] << endl; 22 vi.push_back (5); 23 cout << vi[6] << endl; 24 vi.resize (12); 25 print (vi); 26 vi.resize (2); 27 print (vi); 28 vi.clear (); 29 print (vi); 30 vi.reserve (20); 31 print (vi); 32 cout << vi[19] << endl; 33 vi.reserve (5); 34 print (vi); 35 return 0; 36 }
6.insert()/erase()
insert()/erase() - 根据迭代器参数做插入和删除。
7.sort()/find()
sort()/find() - 全局泛型算法函数,排序(快速)和查找
1 /* 2 *sort() find()举例 3 */ 4 #include <algorithm> 5 #include <vector> 6 #include "print.h" 7 template<typename iterator, typename type> 8 iterator find (iterator begin, iterator end, 9 const type& key) { 10 for (; begin != end; ++begin) 11 if (*begin == key) 12 break; 13 return begin; 14 } 15 bool cmpInt (const int& a, const int& b) { 16 return a > b; 17 } 18 class CmpInt { 19 public: 20 CmpInt (bool less = true) : m_less (less) {} 21 bool operator() (const int& a, const int& b) const{ 22 return m_less ? (a < b) : (a > b); 23 } 24 private: 25 bool m_less; 26 }; 27 int main (void) { 28 int ai[] = {10, 20, 30, 40, 50}; 29 vector<int> vi (ai, &ai[5]); 30 print (vi.begin (), vi.end ()); 31 vector<int>::iterator it = vi.begin (); 32 it = vi.insert (it + 1, 15); 33 print (vi.begin (), vi.end ()); 34 ++++++it; 35 it = vi.erase (it); 36 print (vi.begin (), vi.end ()); 37 cout << *it << endl; // 50 38 vi.insert (vi.begin (), 37); 39 vi.insert (vi.begin () + 2, 43); 40 vi.insert (vi.begin () + 4, 29); 41 vi.push_back (18); 42 vi.push_back (24); 43 print (vi.begin (), vi.end ()); 44 sort (vi.begin (), vi.end ()); 45 print (vi.begin (), vi.end ()); 46 sort (vi.begin (), vi.end (), 47 /*cmpInt*/CmpInt (false)); 48 print (vi.begin (), vi.end ()); 49 it = ::find (vi.begin (), vi.end (), 18); 50 if (it == vi.end ()) 51 cout << "没找到!" << endl; 52 else 53 cout << "找到了:" << *it << endl; 54 return 0; 55 }
1 /*文件名:print.h 2 *描述:泛型的print 3 */ 4 #ifndef _PRINT_H 5 #define _PRINT_H 6 #include <iostream> 7 using namespace std; 8 template<typename iterator> 9 void print (iterator begin, iterator end) { 10 while (begin != end) 11 cout << *begin++ << ‘ ‘; 12 cout << endl; 13 } 14 #endif // _PRINT_H
8.类类型对象的向量
1)无参构造
2)拷贝构造
3)拷贝赋值
4)operator==:find
5)operator</operator基本类型/比较器
1 /* 2 *类类型对象的向量举例 3 * */ 4 #include <vector> 5 #include <algorithm> 6 #include "print.h" 7 class A { 8 public: 9 A (int i = 0) : m_i (i) { 10 cout << "无参构造:" << this << endl; 11 } 12 A (const A& that) : m_i (that.m_i) { 13 cout << "拷贝构造:" << &that << "->" << this 14 << endl; 15 } 16 A& operator= (const A& that) { 17 cout << "拷贝赋值:" << &that << "->" << this 18 << endl; 19 if (&that != this) 20 m_i = that.m_i; 21 return *this; 22 } 23 ~A (void) { 24 cout << "析构函数:" << this << endl; 25 } 26 operator int& (void) { 27 return m_i; 28 } 29 /* 30 operator const int& (void) const { 31 return static_cast<int&> ( 32 const_cast<A&> (*this)); 33 } 34 */ 35 bool operator== (const A& that) const { 36 return m_i == that.m_i; 37 } 38 /* 39 bool operator< (const A& that) const { 40 return m_i < that.m_i; 41 } 42 */ 43 bool operator() (const A& a, const A& b) const { 44 return a.m_i < b.m_i; 45 } 46 private: 47 int m_i; 48 }; 49 int main (void) { 50 cout << "---- 1 ----" << endl; 51 vector<A> va (3); 52 cout << "---- 2 ----" << endl; 53 va.push_back (A ()); 54 cout << "---- 3 ----" << endl; 55 va.erase (va.begin ()); 56 cout << "---- 0 ----" << endl; 57 va[0] = A (10); 58 va[1] = A (50); 59 va[2] = A (70); 60 va.push_back (A (60)); 61 vector<A>::iterator it = find (va.begin (), 62 va.end (), A (70)); 63 if (it == va.end ()) 64 cout << "没找到!" << endl; 65 else 66 cout << "找到了:" << *it << endl; 67 // sort (va.begin (), va.end ()); 68 sort (va.begin (), va.end (), va[0]); 69 print (va.begin (), va.end ()); 70 return 0; 71 } 72
练习:编写程序读取m.dat中的电影票房记录,找出票房前十名,按票房从高到低的顺序写入另一文件中。
1 /* 2 *练习:编写程序读取m.dat中的电影票房记录,找出票房前十名,按票房从高到低的顺序写入另一文件中。 3 */ 4 #include <iostream> 5 #include <fstream> 6 #include <vector> 7 #include <algorithm> 8 using namespace std; 9 class Movie { 10 public: 11 friend istream& operator>> (istream& is, 12 Movie& movie) { 13 return is >> movie.m_title >> movie.m_comp 14 >> movie.m_gross; 15 } 16 friend ostream& operator<< (ostream& os, 17 const Movie& movie) { 18 return os << movie.m_title << ‘ ‘ 19 << movie.m_comp << ‘ ‘ << movie.m_gross; 20 } 21 bool operator< (const Movie& movie) const { 22 return gross () > movie.gross (); 23 } 24 private: 25 double gross (void) const { 26 string str (m_gross); 27 size_t pos = 0; 28 while ((pos = str.find_first_of ("$,", pos)) != 29 string::npos) 30 str.erase (pos, 1); 31 return atof (str.c_str ()); 32 } 33 string m_title; 34 string m_comp; 35 string m_gross; 36 }; 37 bool read (const char* file, vector<Movie>& vm) { 38 ifstream ifs (file); 39 if (! ifs) { 40 perror ("打开票房文件失败"); 41 return false; 42 } 43 Movie movie; 44 while (ifs >> movie) 45 vm.push_back (movie); 46 ifs.close (); 47 return true; 48 } 49 bool write (const char* file, const vector<Movie>& vm){ 50 ofstream ofs (file); 51 if (! ofs) { 52 perror ("打开排行文件失败"); 53 return false; 54 } 55 for (vector<Movie>::const_iterator it = vm.begin(); 56 it != vm.end (); ++it) 57 ofs << *it << endl; 58 ofs.close (); 59 return true; 60 } 61 int main (int argc, char* argv[]) { 62 if (argc < 3) { 63 cerr << "用法:" << argv[0] 64 << " <票房文件> <排行文件>" << endl; 65 return -1; 66 } 67 vector<Movie> vm; 68 if (! read (argv[1], vm)) 69 return -1; 70 sort (vm.begin (), vm.end ()); 71 if (vm.size () > 10) 72 vm.resize (10); 73 if (! write (argv[2], vm)) 74 return -1; 75 return 0; 76 }
四、双端队列(deque)
1.连续内存,下标访问和随机迭代,在首尾两端都可以进行高效的增删。
2.因为要维护首尾两端的开放性,因此双端队列和向量相比,其空间和时间复杂度要略高一些。
3.比vector多了push_front/pop_front,少了reserve。
1 /* 2 *deque举例 3 */ 4 #include <deque> 5 #include <algorithm> 6 #include "print.h" 7 int main (void) { 8 deque<int> di; 9 di.push_back (24); 10 di.push_back (33); 11 di.push_front (18); 12 di.push_front (68); 13 di.insert (di.begin () + 2, 47); 14 print (di.begin (), di.end ()); // 68 18 47 24 33 15 di.pop_back (); 16 di.pop_front (); 17 di.erase (di.begin () + 1); 18 print (di.begin (), di.end ()); // 18 24 19 di.push_back (20); 20 sort (di.begin (), di.end ()); 21 print (di.begin (), di.end ()); // 18 20 24 22 size_t size = di.size (); 23 for (size_t i = 0; i < size; ++i) 24 cout << di[i] << ‘ ‘; 25 cout << endl; 26 di.resize (10); 27 print (di.begin (), di.end ()); 28 return 0; 29 }
五、列表(list)
front/back
push_front/pop_front
push_back/pop_back
insert/erase/remove
size
1.sort
2.unique - 将连续出现的相同元素唯一化。
23 35 35 35 60 12 35 35 99 35 22
| unique
V
23 35 60 12 35 99 35 22
3.splice - 将参数链表的部分或全部剪切到调用链表的特定位置。
void splice (
iterator pos,
list& lst);
list1.splice (pos, list2);
将list2中的全部数据剪切到list1的pos处。
void splice (
iterator pos,
list &lst,
iterator del);
将list2中del所指向数据剪切到list1的pos处。
void splice (
iterator pos,
list& lst,
iterator start,
iterator end );
将list2中start和end之间的数据剪切到list1的pos处。
4.merge - 合并
void merge (list& lst);
void merge (list& lst, Comp compfunction);
将有序的参数列表合并到调用列表中,保证合并后的调用列表依然有序。
注意:任何容器,在结构性修改之前获得的迭代器,有可能因为这种修改而失效,或者不能标识正确的位置,需要重新初始化
1 /* 2 *列表举例 3 */ 4 #include <list> 5 #include "print.h" 6 int main (void) { 7 list<int> li; 8 li.push_back (34); 9 li.push_back (28); 10 li.push_back (34); 11 li.push_back (34); 12 li.push_back (55); 13 li.push_back (34); 14 print (li.begin (), li.end ()); 15 li.unique (); 16 print (li.begin (), li.end ()); 17 li.sort (); 18 print (li.begin (), li.end ()); 19 li.unique (); 20 print (li.begin (), li.end ()); 21 list<int> li2; 22 li2.push_front (100); 23 li2.push_front (200); 24 li2.push_front (300); 25 list<int>::iterator pos = li.begin (); 26 ++pos; 27 // li.splice (pos, li2); 28 list<int>::iterator start = li2.begin (); 29 ++start; 30 // li.splice (pos, li2, start); 31 list<int>::iterator end = li2.end (); 32 li.splice (pos, li2, start, end); 33 print (li.begin (), li.end ()); 34 cout << li2.size () << endl; 35 return 0; 36 }
1 /* 2 *merge()练习 3 */ 4 #include <list> 5 #include "../day12/print.h" 6 int main (void) { 7 int ai1[] = {13, 45, 67, 88, 92, 107}; 8 int ai2[] = {22, 23, 37, 50, 69, 100, 109}; 9 list<int> li1 (ai1, ai1 + 6); 10 list<int> li2 (ai2, ai2 + 7); 11 print (li1.begin (), li1.end ()); 12 print (li2.begin (), li2.end ()); 13 li1.merge (li2); 14 print (li1.begin (), li1.end ()); 15 print (li2.begin (), li2.end ()); 16 list<int>::iterator it = li1.begin (); 17 li1.insert (it, 1000); 18 it = li1.begin (); 19 li1.insert (it, 2000); 20 print (li1.begin (), li1.end ()); 21 return 0; 22 }
六、堆栈
stack 底层容器vector/deque/list
push push_back
pop pop_back
top back
size size
empty empty
... ...
#include <stack>
stack<int, vector<int> > si;
stack<string, list<string> > ss;
stack<double> sd; // 缺省底层容器deque
template<typename T, typename C>
stack {
public:
void push (const T& data) {
m_container.push_back (data);
}
void pop (void) {
m_conainer.pop_back ();
}
T& top (void) {
return m_container.back ();
}
private:
C m_container;
};
1 /* 2 * 适配器练习- stack 3 * 4 * */ 5 #include <iostream> 6 #include <stack> 7 #include <vector> 8 using namespace std; 9 int main (void) { 10 stack<string, vector<string> > ss; 11 ss.push ("吃饭"); 12 ss.push ("喜欢"); 13 ss.push ("偶"); 14 while (! ss.empty ()) { 15 cout << ss.top (); 16 ss.pop (); 17 } 18 cout << endl; 19 return 0; 20 }
七、队列
queue 底层容器deque/list (p.s.不可以是vector,因为vector没有提供pop_front)
push push_back
pop pop_front
front front
back back
size size
empty empty
...
queue<int, list<int> > qi;
queue<string> qs; // 缺省底层容器deque
1 /* 2 * 适配器练习- queue 3 * */ 4 #include <iostream> 5 #include <queue> 6 #include <list> 7 using namespace std; 8 int main (void) { 9 queue<string, list<string> > qs; 10 qs.push ("我"); 11 qs.push ("要"); 12 qs.push ("吃"); 13 qs.push ("饭"); 14 while (! qs.empty ()) { 15 cout << qs.front (); 16 qs.pop (); 17 } 18 cout << endl; 19 return 0; 20 }
八、优先队列(priority_queue)
优者先出
底层容器:vector/deque/list,缺省deque
通过类型实参以比较器的形式定义比较规则
1 /* 2 * 适配器练习- priority queue 3 * 4 * */ 5 #include <iostream> 6 #include <queue> 7 using namespace std; 8 class Student { 9 public: 10 Student (const string& name, float score) : 11 m_name (name), m_score (score) {} 12 void print (void) const { 13 cout << m_name << "," << m_score << endl; 14 } 15 bool operator< (const Student& student) const { 16 return m_score > student.m_score; 17 } 18 private: 19 string m_name; 20 float m_score; 21 }; 22 class CmpInt { 23 public: 24 bool operator() (int a, int b) { 25 return a > b; 26 } 27 }; 28 int main (void) { 29 // priority_queue<int> pqi; 30 priority_queue<int, deque<int>, CmpInt> pqi; 31 pqi.push (23); 32 pqi.push (12); 33 pqi.push (23); 34 pqi.push (27); 35 pqi.push (19); 36 while (! pqi.empty ()) { 37 cout << pqi.top () << ‘ ‘; 38 pqi.pop (); 39 } 40 cout << endl; 41 priority_queue<Student> pqs; 42 pqs.push (Student ("张飞", 65)); 43 pqs.push (Student ("关羽", 60)); 44 pqs.push (Student ("赵云", 85)); 45 pqs.push (Student ("刘备", 95)); 46 pqs.push (Student ("曹操", 25)); 47 while (! pqs.empty ()) { 48 pqs.top ().print (); 49 pqs.pop (); 50 } 51 return 0; 52 }
九、映射(map)
1.key-value对(pair)的容器,通过pair表示key-value对。
post script:关于pair
template<typename FIRST, typename SECOND>
class pair {
prublic:
...
FIRST first;
SECOND second;
};
2.key唯一且升序。
3.支持下标运算符,可以用[key]访问value。
4.可以通过比较器类型自定义key升序的规则。
1 /* 2 * map练习 3 * */ 4 #include <iostream> 5 #include <map> 6 using namespace std; 7 class Candidate { 8 public: 9 Candidate (const char* name = "") : 10 m_name (name), m_votes (0) {} 11 const string& name (void) const { 12 return m_name; 13 } 14 size_t votes (void) const { 15 return m_votes; 16 } 17 void vote (void) { 18 ++m_votes; 19 } 20 private: 21 string m_name; 22 size_t m_votes; 23 }; 24 int main (void) { 25 map<char, Candidate> mc; 26 mc.insert (make_pair (‘B‘, "赵云")); 27 mc.insert (pair<char, Candidate> (‘A‘, "张飞"));//构造一个pair的对象放入map对象里 28 mc[‘D‘] = "刘备"; 29 mc[‘E‘] = "曹操"; 30 mc[‘C‘] = "关羽"; 31 mc[‘D‘] = "黄忠";//因为key唯一且升序,所以这里会造成‘D‘不再与"刘备"形成映射 32 mc.insert (pair<char, Candidate> (‘A‘, "马超"));//使用map的成员函数insert时候,insert判断出key已经与其他value形成映射,那么会忽略此次的insert 33 typedef map<char, Candidate>::iterator IT; 34 typedef map<char, Candidate>::const_iterator CIT; 35 for (size_t i = 0; i < 10; ++i) { 36 for (CIT it=mc.begin (); it != mc.end (); ++it) 37 cout << ‘(‘ << it->first << ‘)‘ 38 << it->second.name () << ‘ ‘; 39 cout << endl << "请投下宝贵的一票:" << flush; 40 char key; 41 cin >> key; 42 IT it = mc.find (key); 43 if (it == mc.end ()) { 44 cout << "此票作废!" << endl; 45 continue; 46 } 47 it->second.vote (); 48 } 49 CIT win = mc.begin (); 50 for (CIT it = mc.begin (); it != mc.end (); ++it){ 51 cout << it->second.name () << "获得" 52 << it->second.votes () << "票。" << endl; 53 if (it->second.votes () > win->second.votes ()) 54 win = it; 55 } 56 cout << "恭喜" << win->second.name () << "同学当选" 57 "为首席保洁员!" << endl; 58 return 0; 59 }
1 /* 2 *练习:编写程序,统计一个文本文件中每个单词出现的频率。按照词汇表的顺序打印输出。 3 *apple : 2 4 *beijing : 2 5 *c++ : 3 6 *... 7 * */ 8 #include <iostream> 9 #include <fstream> 10 #include <map> 11 #include <cstring> 12 using namespace std; 13 14 class CmpStr { 15 public: 16 bool operator() (const string& a, 17 const string& b) const { 18 return strcasecmp (a.c_str (), 19 b.c_str ()) < 0; 20 } 21 }; 22 23 int main (int argc, char* argv[]) { 24 if (argc < 2) { 25 cerr << "用法:" << argv[0] << " <文件>"<<endl; 26 return -1; 27 } 28 ifstream ifs (argv[1]); 29 if (! ifs) { 30 perror ("打开文件失败"); 31 return -1; 32 } 33 map<string, int, CmpStr> msi; 34 string word; 35 while (ifs >> word) 36 ++msi[word]; 37 ifs.close (); 38 for (map<string, int>::iterator it = msi.begin (); 39 it != msi.end (); ++it) 40 cout << it->first << " : " << it->second<<endl; 41 42 return 0; 43 }
十、集合
1 /* 2 *set练习 3 */ 4 #include <iostream> 5 #include <set> 6 #include <fstream> 7 using namespace std; 8 int main (void) { 9 ifstream ifs ("test.txt"); 10 set<string> ss; 11 string word; 12 while (ifs >> word) 13 ss.insert (word); 14 ifs.close (); 15 for (set<string>::iterator it = ss.begin (); 16 it != ss.end (); ++it) 17 cout << *it << endl; 18 cout << "共" << ss.size () << "个不同单词。" 19 << endl; 20 return 0; 21 }
十一、多重映射
key可重复,升序,迭代时key相同的元素相邻。
1 /* 2 *multimap练习 3 */ 4 #include <iostream> 5 #include <map> 6 using namespace std; 7 int main (void) { 8 multimap<string, int> msi; 9 msi.insert (make_pair ("张飞", 100000)); 10 msi.insert (make_pair ("赵云", 200000)); 11 msi.insert (make_pair ("张飞", 300000)); 12 msi.insert (make_pair ("关羽", 400000)); 13 msi.insert (make_pair ("赵云", 500000)); 14 msi.insert (make_pair ("关羽", 600000)); 15 typedef multimap<string, int>::const_iterator CIT; 16 for (CIT it = msi.begin (); it != msi.end ();++it) 17 cout << it->first << " : " << it->second<<endl; 18 cout << "-------------" << endl; 19 for (CIT it = msi.begin (); it != msi.end();/*++it*/){ 20 string key = it->first; 21 CIT end = msi.upper_bound (key);//upper_bound(key)成员函数返回和参数key相匹配的所有记录中最后一条记录的下一条记录的迭代器 22 int sum = 0; 23 for (; it != end; ++it) 24 sum += it->second; 25 cout << key << " : " << sum << endl; 26 // --it; 27 } 28 return 0; 29 }
十二、多重集合
1 /* 2 *multiset练习 3 */ 4 #include <iostream> 5 #include <set> 6 using namespace std; 7 int main (void) { 8 const char* candidates[] = { 9 "张飞", "赵云", "关羽", "刘备", "曹操", NULL}; 10 multiset<string> ms; 11 for (size_t i = 0; i < 10; ++i) { 12 for (size_t i = 0; candidates[i]; ++i) 13 cout << ‘(‘ << char (‘A‘ + i) << ‘)‘ 14 << candidates[i] << ‘ ‘; 15 cout << endl << "请投下您庄严的一票:" <<flush; 16 char key; 17 cin >> key; 18 if (key < ‘A‘ || ‘E‘ < key) { 19 cout << "此票作废!" << endl; 20 continue; 21 } 22 ms.insert (candidates[key-‘A‘]); 23 } 24 multiset<string>::iterator win = ms.begin (); 25 for (multiset<string>::iterator it = ms.begin (); 26 it != ms.end (); ++it) { 27 cout << *it << "获得" << ms.count (*it) 28 << "票。" << endl; 29 if (ms.count (*it) > ms.count (*win)) 30 win = it; 31 it = ms.upper_bound (*it); 32 --it; 33 } 34 cout << "热烈祝贺" << *win << "当选垃圾长!" 35 << endl; 36 return 0; 37 }
十三、泛型算法
1.STL中包含60种泛型算法,其中包含23种非修改算法,如find,37种修改算法,如sort。
2.STL中的泛型算法多数都会迭代器实现对容器元素的访问。
3.STL中的泛型算法凡是涉及到比较大小的算法,都支持两种比较方案——“<”运算符和比较器函数对象。
4.除了STL中的容器以外,程序员也可以使自定义的容器,获得STL泛型算法的支持,只要改自定义类型能够支持此算法对迭代器的使用规则即可。
1 /* 2 *练习:假设现在有任意两个容器,请实现一个泛型的容器拷贝函数,用将一个容器中数据拷贝到另一个容器中。 3 */ 4 #include <vector> 5 #include <deque> 6 #include <list> 7 8 template<typename iterator> 9 void print(iterator begin, iterator end) 10 { 11 while (begin != end) { 12 cout << *begin++ << ‘ ‘ << flush; 13 } 14 cout << endl; 15 return 0; 16 } 17 18 template<typename IT1, typename IT2> 19 void my_copy (IT1 begin, IT1 end, IT2 to) { 20 while (begin != end) 21 //*(to++) = *(begin++); 22 *to++ = *begin++; 23 } 24 25 int main (void) { 26 int arr1[5] = {10, 20, 30, 40, 50}; 27 int arr2[5]; 28 copy (arr1, arr1 + 5, arr2); 29 print (arr2, arr2 + 5); 30 vector<int> vec (5); 31 copy (arr1, arr1 + 5, vec.begin ()); 32 print (vec.begin (), vec.end ()); 33 deque<int> deq (5); 34 copy (vec.begin (), vec.end (), deq.begin ()); 35 print (deq.begin (), deq.end ()); 36 list<int> lst (5); 37 copy (deq.begin (), deq.end (), lst.begin ()); 38 print (lst.begin (), lst.end ()); 39 return 0; 40 }