Standard C++ Episode 11

一、标准模板库(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 &nbsp;* */
 8 #include <iostream>
 9 #include <fstream>
10 #include <map>
11 #include <cstring>
12 using namespace std;
13
14 class CmpStr {
15 public:
16 &nbsp;&nbsp; &nbsp;bool operator() (const string& a,
17 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const string& b) const {
18 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return strcasecmp (a.c_str (),
19 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;b.c_str ()) < 0;
20 &nbsp;&nbsp; &nbsp;}
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 }
时间: 2024-10-18 00:43:00

Standard C++ Episode 11的相关文章

Standard C episode 1

计算机内存可以记录大量的信息,只有记录在内存中的信息才是可以使用的.计算机的内存管理者是操作系统.程序可以根据需要向操作系统申请存储区,所有存储区必须先申请并经过操作系统分配后才能由程序使用.我们知道计算机里的信息可以简单划分为: /指令       /控制信息 信息 -            \控制字       \数据信息                     |              /              \      数值信息     非数值信息       /    \ 

Standard C Episode 3

程序语言中的控制流语句用于控制各计算操作执行的次序.控制流结构有:(1)顺序结构(2)分支结构(3)循环结构 if...else语句是经典的分支结构控制语句,同样"switch (表达式)...case 常量表达式" 语句也可以实现分支处理."表达式"可以是任何表达式,"常量表达式"也可以是任何常量表达式.case分支一般包含多条语句时也不必用大括号括起来,因 为每一个case分支只会给出switch分支结构中语句执行的开始位置,而不确定终止位置

Standard C Episode 5

理解变量标识符的作用域和可见性,以及变量生存期. (1)标识符的作用域和可见性     作用域:作用域是一个标识符在源程序中有效的区域.     可见性:程序运行到某一点,能够引用到的标识符,就是该处可见的标识符. (2)变量生存期:     变量的生存期就是指变量从创建到销毁的时间范围.变量按照生存期分“静态生存期”和“动态生存期”.静态生存期:如果变量的生存期与程序的运行期相同,则称该变量具有“静态生存期”; 动态生存期:变量生存期始于创建声明点,结束于作用域结束处. 注意:源程序声明(定义

Standard C Episode 2

源程序中,但凡可以出现某种类型的数据的地方都可以用同类型的表达式替换.一个表达式的类型,取决于多个方面. 操作符有单目操作符和双目操作符, 还有三目操作符(? : 是C语言唯一的一个三目操作符)."目"指的是操作数的个数! C语言没有指定同一操作符的多个操作数的计算顺序(除了&& || ? : 和,).所以语句x = f() + g();的计算结果依赖不同的编译器. 1 /* 2 * 文件名: 3mu.c 3 * 描述:(1)一个表达式的类型取决于多个方面(表达式的操作

Standard C Episode 4

稍微简单的复杂数据类型:数组 计算机程序处理的对象是数据信息(计算机中的信息包括数据信息和控制信息),计算机内存可以存储大量信息,姑且可以认为只有存储在内存中的数据信息才是可 以使用的.内存由操作系统管理,程序要使用内存存储空间需要向操作系统申请并被成功分配后才可以使用,C语言提供的变量声明(定义)语句可以实现向操作系 统申请存储空间. C语言提供的变量声明(定义)语句实现向操作系统申请存储区(存储空间),变量名有"两个代表",一是代表所申请到的存储区,一是代表存储区里面存放的数 据信

Standard C Episode 6

字符串.字符串是以'\0'结尾的字符序列.C语言字符串在内存中的存储规则:按照串中字符出现的顺序在内存中连续存储,末尾是字符串结束符'\0'. 注:'\0'(查ASCII码表可知'\0'就是0)是表示字符串的字符,它的位置决定了一个字符串中有效字符的个数. 字符串常量.字符串常量在源程序词法记号中属于"文字",它和其他文字"数字.布尔文字.以及字符"一样.但区别是“字符串常量文字代表的是首字符地址”. 注:编译器编译时候会把源程序中重复出现的相同文字只存储一回.多个

Standard C Episode 8

C语言函数和程序结构 通过函数可以把大的计算任务分解成若干个较小任务,从而使得思路更加清晰,同时函数也大大提高了代码的复用率,提高了工作效率.要注意的是多函数之间应该尽可能地高聚合低耦合.另一方面,一个程序可以保存在一个或者多个源文件中.各个文件可以单独编译. 注意:一般地,头文件中不会放那些在程序运行时发生具体效应的语句.例如声明(定义)一个变量的语句是不会放在头文件中的.再例如结构体声明(定义)语句就可以放头文件里,但结构体变量声明(定义)语句是不会放在头文件中的. make工具可以用来进行

Standard C Episode 9

typedef关键字可以给数据类型起别名. 结构体.结构体可以如下定义一个结构体变量 1 /* 2 * 结构体 3 * */ 4 #include <stdio.h> 5 /*struct { 6 int age; 7 char gender; 8 float height; 9 } student;//声明(定义)无名结构体的同时定义了结构体变量student 10 */ 11 /*struct student { 12 int age; 13 char gender; 14 float h

Standard C Episode 10

标准库函数malloc/calloc/realloc以及free的堆内存分配与回收 1 /* 2 * malloc练习 3 * 4 * */ 5 6 #include <stdlib.h> 7 #include <stdio.h> 8 9 int main() 10 { 11 int *p_value = NULL; 12 13 p_value = (int *) malloc (1 * sizeof(int)); 14 if (p_value) { 15 printf("