• STL容器之vector


    【1】模板类vector

    模板类vector可理解为广义数组。广义数组,即与类型无关的数组,具有与数组相同的所有操作。

    那么,你或许要问:既然C++语言本身已提供了一个序列式容器array,为什么还要vector呢?

    我们一直强调,事物总是朝向更先进的方向螺旋式发展与进化。这个问题其中的道理也不例外。

    vector的数据安排及操作方式与array非常相似。两者唯一区别在于空间运用的灵活性。

    array是静态空间,一旦配置不能改变。要想换个大(或小)点的房子,一切琐细得由客户端自己料理(步骤如下):

    首先,配置一块新空间,然后从旧地址将元素逐一搬往新地址,最后把原来的空间释放还给系统。

    vector是动态空间,不仅可以在运行期再确定容器容量大小,而且随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。

    所以,相比较array,运用vector对内存的合理灵活性利用有很大的帮助。

    【2】vector应用实例

    (1)有构造函数才会有容器。模板类vector的构造函数及构建实例。代码如下:

     1 #include <iostream>
     2 #include <vector>
     3 #include <memory>
     4 using namespace std;
     5 
     6 void main()
     7 {
     8 /* C++11 
     9     default (1)    
    10     explicit vector (const allocator_type& alloc = allocator_type());
    11     // 构建一个空容器(默认构造函数)。
    12 
    13     fill (2)    
    14     explicit vector (size_type n);
    15     vector (size_type n, const value_type& val,
    16             const allocator_type& alloc = allocator_type());
    17     // 构建一个容器。容器存储n个元素,每个元素的初始值为val(如果提供)。
    18 
    19     range (3)     
    20     template <class InputIterator>
    21     vector (InputIterator first, InputIterator last,
    22             const allocator_type& alloc = allocator_type());
    23     // 构建一个容器。容器存储元素与源容器中[first,last)区间的元素内容一样。
    24     // 内容指存放元素的值及位置和[first,last)区间中完全一样,方向也要一致。
    25 
    26     copy (4)     
    27     vector (const vector& x);
    28     vector (const vector& x, const allocator_type& alloc);
    29     // 拷贝构造函数。构建一个容器,逐个复制源容器x中的每一个元素,存放到本容器中,方向也保持一致。
    30 
    31     move (5)     
    32     vector (vector&& x);
    33     vector (vector&& x, const allocator_type& alloc);
    34     // 移动构造函数。如果新的分配器alloc和x的分配器alloc不一样,那么将移动源容器x里面的元素到新的vector。
    35     // 如果分配器是一样的,那么将直接转换其所有权。
    36     // 将右值引用中容器x所有元素的所有权移动到新的vector中,避免付出昂贵的复制代价。
    37 
    38     initializer list (6)    
    39     vector (initializer_list<value_type> il,
    40             const allocator_type& alloc = allocator_type());
    41     // 初始化列表构造函数。从初始化列表il中复制每一个元素,放到新的vector中,方向与列表保持一致。
    42 */
    43     // default (1)
    44     vector<int> vInt1;
    45 
    46     // fill (2)
    47     int n;
    48     cin >> n;
    49     vector<int> vInt2(n);
    50 
    51     vector<int> vInt3(10);
    52 
    53     vector<int> vInt4(10, 100);
    54 
    55     // range(3)
    56     vector<int> vInt5(vInt4.begin(), vInt4.end());
    57 
    58     int myInt[] = {1, 2, 3, 4, 5};
    59     vector<int> vInt6(myInt, myInt + sizeof(myInt) / sizeof(int));
    60 
    61     // copy(4)
    62     vector<int> vInt7(vInt4);
    63 
    64     // move(5)
    65     vector<unique_ptr<string> > vUS = vector<unique_ptr<string> >({
    66         unique_ptr<string> (new string("Qin")), 
    67         unique_ptr<string> (new string("Liu")),
    68         unique_ptr<string> (new string("Wang")),
    69         unique_ptr<string> (new string("Zhang"))});
    70 
    71     // initializer_list(6)
    72     vector<int> vInt8({10, 20, 30, 40, 50});
    73 }

    对于任何一个类而言,构造函数是相当重要的,其所有对象呈现的操作方法都与构造函数息息相关。

    类的构造函数为对象先天性的行为铺垫(比如:类的构造函数若多一个参数,那么类将会有很多成员方法为这个参数服务)。

    下面的实例演示使用vector模板方便创建动态分配数组的优势(内置数组无法完成)

     1 #include <iostream>
     2 #include <vector>
     3 #include <string>
     4 using namespace std;
     5 
     6 void main()
     7 {
     8     cout << "请输入预处理学生数目:
    ";
     9     int nStudents;
    10     cin >> nStudents;
    11     vector<string> names(nStudents);
    12     vector<int> scores(nStudents);
    13     cout << "请输入" << nStudents << " 个学生的姓名和英语成绩 (0 ~ 100)。
    ";
    14     int i;
    15     for (i = 0; i < nStudents; ++i)
    16     {
    17         cout << "姓名 No" << i + 1 << ": ";
    18         cin >> names[i];
    19         cout << "成绩 (0 ~ 100):";
    20         cin >> scores[i];
    21         cin.get();
    22     }
    23     cout << "输入所有学生信息结束。
    ";
    24     cout << "打印输入姓名及成绩如下:
    ";
    25     for (i = 0; i < nStudents; ++i)
    26     {
    27         cout << names[i] << "	" << scores[i] << endl;
    28     }
    29 
    30     cin.get();
    31 }
    32 // Run out:
    33 /*
    34 请输入预处理学生数目:
    35 5
    36 请输入5 个学生的姓名和英语成绩 (0 ~ 100)。
    37 姓名 No1: sun
    38 成绩 (0 ~ 100):89
    39 姓名 No2: li
    40 成绩 (0 ~ 100):87
    41 姓名 No3: wang
    42 成绩 (0 ~ 100):90
    43 姓名 No4: qin
    44 成绩 (0 ~ 100):98
    45 姓名 No5: zhang
    46 成绩 (0 ~ 100):69
    47 输入所有学生信息结束。
    48 打印输入姓名及成绩如下:
    49 sun     89
    50 li      87
    51 wang    90
    52 qin     98
    53 zhang   69
    54 */

    vector模板更多的方法请看下节。

    (2)常用成员方法应用示例如下代码:

      1 #include <iostream>
      2 #include <vector>
      3 using namespace std;
      4 
      5 void printVectorValue(vector<int> & vInt)
      6 {
      7     for (vector<int>::iterator pt = vInt.begin(); pt != vInt.end(); ++pt)
      8     {
      9         cout << *pt << "	";
     10     }
     11     cout << endl;
     12 }
     13 
     14 void main()
     15 {
     16 //  vector对象的常用方法以及应用示例如下:
     17     cout << "动态构建一个整型容器(请输入整数值,0时退出):
    "; 
     18     vector<int> vMyInts;
     19     int nTemp;
     20     while (cin >> nTemp && nTemp != 0)
     21     {
     22         vMyInts.push_back(nTemp);
     23     }
     24     cout << "您输入 " << vMyInts.size() << "个元素,分别如下: " << endl;
     25     printVectorValue(vMyInts);
     26     cout << "构建整型容器vMyInts完成" << endl << endl;
     27 
     28 //(1)a.assign(b.begin(), b.begin() + 3); // b为向量,将b的0~2个元素构成的向量赋给a
     29     cout << "(1) assign方法 :" << endl;
     30     vector<int> vA1;
     31     vA1.assign(vMyInts.begin(), vMyInts.begin() + 3);
     32     cout << "容器vA1元素如下:" << endl;
     33     printVectorValue(vA1);
     34     cout << "(1) assign方法应用示例完成。" << endl << endl;
     35 
     36 //(2)a.assign(4, 2); // 容器a只含4个元素,且每个元素值为2
     37     cout << "(2) assign(4, 2)方法 :" << endl;
     38     vector<int> vA2;
     39     vA2.assign(4, 12);
     40     cout << "容器vA2元素如下:" << endl;
     41     printVectorValue(vA2);
     42     cout << "(2) assign(4, 2)方法应用示例完成。" << endl << endl;
     43 
     44 //(3)a.back(); // 返回容器a的最后一个元素
     45     cout << "(3) back方法 :" << endl;
     46     cout << "vMyInts容器的最后一个元素是:" << vMyInts.back() << endl;
     47     cout << "(3) back方法应用示例完成。" << endl << endl;
     48 
     49 // (4)a.front(); // 返回容器a的第一个元素
     50     cout << "(4) front方法 :" << endl;
     51     cout << "vMyInts容器的最前一个元素是:" << vMyInts.front() << endl;
     52     cout << "(4) front方法应用示例完成。" << endl << endl;
     53 
     54 // (5)a[i]; // 返回a的第i个元素,当且仅当a[i]存在
     55     cout << "(5) a[i] 方法 :" << endl;
     56     cout << "vMyInts容器的第2个元素是:" << vMyInts[2 - 1] << endl;
     57     cout << "(5) a[i]方法应用示例完成。" << endl << endl;
     58 
     59 // (6)a.clear(); // 清空容器a中的元素
     60     cout << "(6) clear() 方法 :" << endl;
     61     cout << "清空前,vA2容器中的元素为: " << endl;
     62     printVectorValue(vA2);
     63     vA2.clear();
     64     cout << "清空后,vA2容器中的元素为: " << endl;
     65     printVectorValue(vA2);
     66     cout << "(6) clear()方法应用示例完成。" << endl << endl;
     67 
     68 // (7)a.empty(); // 判断容器a是否为空,空则返回ture,不空则返回false
     69     cout << "(7) empty() 方法 :" << endl;
     70     cout << "vA2容器是否为空:" << vA2.empty() << endl;
     71     cout << "(7) empty()方法应用示例完成。" << endl << endl;
     72 
     73 // (8)a.pop_back(); // 删除容器a的最后一个元素
     74     cout << "(8) pop_back() 方法 :" << endl;    vA2.clear();
     75     cout << "删除前,vMyInts容器中的元素为: " << endl;
     76     printVectorValue(vMyInts);
     77     vMyInts.pop_back();
     78     cout << "删除最后一个元素后,vMyInts容器中的元素为: " << endl;
     79     printVectorValue(vMyInts);
     80     cout << "(8) pop_back()方法应用示例完成。" << endl << endl;
     81 
     82 // (9)a.erase(a.begin() + 1, a.begin() + 3); 
     83 //  删除容器a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从[a.begin() + 1, a.begin() + 3)(前闭后开区间)
     84     cout << "(9) erase() 方法 :" << endl;    vA2.clear();
     85     cout << "删除前,vMyInts容器中的元素为: " << endl;
     86     printVectorValue(vMyInts);
     87     vMyInts.erase(vMyInts.begin() + 1, vMyInts.begin() + 3);
     88     cout << "删除后,vMyInts容器中的元素为: " << endl;
     89     printVectorValue(vMyInts);
     90     cout << "(9) erase()方法应用示例完成。" << endl << endl;
     91 
     92 // (10)a.push_back(5); // 在容器a的最后一个向量后插入一个元素,其值为5
     93     cout << "(10) push_back() 方法 :" << endl;    vA2.clear();
     94     cout << "添加前,vMyInts容器中的元素为: " << endl;
     95     printVectorValue(vMyInts);
     96     vMyInts.push_back(99);
     97     cout << "添加后,vMyInts容器中的元素为: " << endl;
     98     printVectorValue(vMyInts);
     99     cout << "(10) push_back()方法应用示例完成。" << endl << endl;
    100 
    101 // (11)a.insert(a.begin() + 1, 5); 
    102 //  在容器a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4 插入元素后为1,5,2,3,4
    103     cout << "(11) insert() 方法 :" << endl;
    104     cout << "插入前,vMyInts容器中的元素为: " << endl;
    105     printVectorValue(vMyInts);
    106     vMyInts.insert(vMyInts.begin() + 1, 11);
    107     cout << "插入后,vMyInts容器中的元素为: " << endl;
    108     printVectorValue(vMyInts);
    109     cout << "(11) insert()方法应用示例完成。" << endl << endl;
    110 
    111 // (12)a.insert(a.begin() + 1, 3, 5); // 在容器a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
    112     cout << "(12) insert() 方法 :" << endl;
    113     cout << "插入前,vMyInts容器中的元素为: " << endl;
    114     printVectorValue(vMyInts);
    115     vMyInts.insert(vMyInts.begin() + 1, 2, 12);
    116     cout << "插入后,vMyInts容器中的元素为: " << endl;
    117     printVectorValue(vMyInts);
    118     cout << "(12) insert()方法应用示例完成。" << endl << endl;
    119 
    120 // (13)a.insert(a.begin() + 1, b + 3, b + 6); 
    121 //  b为数组。在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b + 6)
    122 //  b为1,2,3,4,5,9,8  插入元素后为1,4,5,9,2,3,4,5,9,8
    123     cout << "(13) insert() 方法 (容器示例):" << endl;
    124     cout << "插入前,vMyInts容器中的元素为: " << endl;
    125     printVectorValue(vMyInts);
    126     cout << "插入前,vA1容器中的元素为: " << endl;
    127     printVectorValue(vA1);
    128     vA1.insert(vA1.begin() + 1, vMyInts.begin() + 3, vMyInts.begin() + 6);
    129     cout << "插入后,vMyInts容器中的元素为: " << endl;
    130     printVectorValue(vMyInts);
    131     cout << "插入后,vA1容器中的元素为: " << endl;
    132     printVectorValue(vA1);
    133     cout << "(13) insert()方法应用示例完成。" << endl << endl;
    134 
    135     cout << "(13) insert() 方法 (数组示例):" << endl;
    136     cout << "插入前,vA1容器中的元素为: " << endl;
    137     printVectorValue(vA1);
    138     cout << "数组中的元素为: {1, 2, 3, 4, 5, 6}" << endl;
    139     int nArrB[] = {1, 2, 3, 4, 5, 6};
    140     vA1.insert(vA1.begin() + 1, nArrB + 1, nArrB + 4);
    141     cout << "插入后,vA1容器中的元素为: " << endl;
    142     printVectorValue(vA1);
    143     cout << "(13) insert()方法应用示例完成。" << endl << endl;
    144 
    145 // (14)a.size(); // 返回容器a中元素的个数;
    146     cout << "(14) size() 方法: " << endl;
    147     cout << "vA1容器中的元素为: " << endl;
    148     printVectorValue(vA1);
    149     cout << "vA1容器中元素个数为:" << vA1.size() << endl;
    150     cout << "(14) size()方法应用示例完成。" << endl << endl;
    151 
    152 // (15)a.capacity(); // 返回容器a的容量
    153     cout << "(15) capacity() 方法: " << endl;
    154     cout << "vA1容器的容量为:" << vA1.capacity() << endl;
    155     cout << "(15) capacity()方法应用示例完成。" << endl << endl;
    156 
    157 // (16)a.rezize(10); // 将a的现有元素个数调至10个,多则删,少则补,其值随机
    158     cout << "(16) resize() 方法: " << endl;
    159     cout << "重新分配大小前,vA1容器中元素为: " << endl;
    160     printVectorValue(vA1);
    161     vA1.resize(6);
    162     cout << "vA1.resize(6) 重新分配大小后,vA1容器中元素为:" << endl;
    163     printVectorValue(vA1);
    164     cout << "(16) resize()方法应用示例完成。" << endl << endl;
    165 
    166 // (17)a.rezize(10, 2); // 将容器a的现有元素个数调至10个,多则删,少则补其值为2
    167     cout << "(17) resize() 方法: " << endl;
    168     cout << "重新分配大小前,vA1容器中元素为: " << endl;
    169     printVectorValue(vA1);
    170     vA1.resize(10, 100);
    171     cout << "vA1.resize(10, 110) 重新分配大小后,vA1容器中元素为:" << endl;
    172     printVectorValue(vA1);
    173     cout << "(17) resize()方法应用示例完成。" << endl << endl;
    174 
    175 // (18)a.reserve(100);
    176 //  将容器a的容量(capacity)扩充至100,也就是说现在测试 a.capacity();的时候返回值是100。
    177 //  这种操作只有在需要给a添加大量数据的时候才有意义,
    178 //  因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能。) 
    179     cout << "(18) reserve() 方法: " << endl;
    180     cout << "扩容前,vA1容器的容量为:" << vA1.capacity() << endl;
    181     vA1.reserve(30);
    182     cout << "扩容后,vA1容器的容量为:" << vA1.capacity() << endl;
    183     cout << "(18) reserve()方法应用示例完成。" << endl << endl;
    184 
    185 // (19)a.swap(b); // b为容器,将a中的元素和b中的元素进行整体性交换
    186     cout << "(19) swap() 方法: " << endl;
    187     cout << "vA1容器中的元素为: " << endl;
    188     printVectorValue(vA1);
    189     cout << "vMyInts容器中的元素为: " << endl;
    190     printVectorValue(vMyInts);
    191     vA1.resize(5);
    192     vMyInts.resize(5);
    193     vA1.swap(vMyInts);
    194     cout << "vA1容器中的元素为: " << endl;
    195     printVectorValue(vA1);
    196     cout << "vMyInts容器中的元素为: " << endl;
    197     printVectorValue(vMyInts);
    198     cout << "(19) swap() 方法应用示例完成。 " << endl << endl;
    199 
    200 // (20)a = b; // b为容器,将一个对象赋给另一个对象
    201     cout << "(20) 赋值方法: " << endl;
    202     cout << "vA1容器中的元素为: " << endl;
    203     printVectorValue(vA1);
    204     vector<int> vTemp = vA1;
    205     cout << " vTemp = vA1 后,vTemp 容器中的元素为: " << endl;
    206     printVectorValue(vTemp);
    207     cout << "(20) 赋值方法应用示例完成。 " << endl << endl;
    208 
    209 // (20)a == b; // b为容器,向量的比较操作还有!=,>=,<=,>,<
    210     cout << "(21) 比较操作: " << endl;
    211     cout << "vA1容器中的元素为: " << endl;
    212     printVectorValue(vA1);
    213     cout << " vTemp 容器中的元素为: " << endl;
    214     printVectorValue(vTemp);
    215     cout << "vA1 == vTemp 比较:" << (vA1 == vTemp) << endl; 
    216     cout << "(21) 比较操作应用示例完成。 " << endl << endl; 
    217     cin >> nTemp;
    218 }
    219 // Run out
    220 /*
    221 动态构建一个整型容器(请输入整数值,0时退出):
    222 12
    223 23
    224 34
    225 45
    226 56
    227 67
    228 78
    229 89
    230 90
    231 0
    232 您输入 9个元素,分别如下:
    233 12      23      34      45      56      67      78      89      90
    234 构建整型容器vMyInts完成
    235 
    236 (1) assign方法 :
    237 容器vA1元素如下:
    238 12      23      34
    239 (1) assign方法应用示例完成。
    240 
    241 (2) assign(4, 2)方法 :
    242 容器vA2元素如下:
    243 12      12      12      12
    244 (2) assign(4, 2)方法应用示例完成。
    245 
    246 (3) back方法 :
    247 vMyInts容器的最后一个元素是:90
    248 (3) back方法应用示例完成。
    249 
    250 (4) front方法 :
    251 vMyInts容器的最前一个元素是:12
    252 (4) front方法应用示例完成。
    253 
    254 (5) a[i] 方法 :
    255 vMyInts容器的第2个元素是:23
    256 (5) a[i]方法应用示例完成。
    257 
    258 (6) clear() 方法 :
    259 清空前,vA2容器中的元素为:
    260 12      12      12      12
    261 清空后,vA2容器中的元素为:
    262 
    263 (6) clear()方法应用示例完成。
    264 
    265 (7) empty() 方法 :
    266 vA2容器是否为空:1
    267 (7) empty()方法应用示例完成。
    268 
    269 (8) pop_back() 方法 :
    270 删除前,vMyInts容器中的元素为:
    271 12      23      34      45      56      67      78      89      90
    272 删除最后一个元素后,vMyInts容器中的元素为:
    273 12      23      34      45      56      67      78      89
    274 (8) pop_back()方法应用示例完成。
    275 
    276 (9) erase() 方法 :
    277 删除前,vMyInts容器中的元素为:
    278 12      23      34      45      56      67      78      89
    279 删除后,vMyInts容器中的元素为:
    280 12      45      56      67      78      89
    281 (9) erase()方法应用示例完成。
    282 
    283 (10) push_back() 方法 :
    284 添加前,vMyInts容器中的元素为:
    285 12      45      56      67      78      89
    286 添加后,vMyInts容器中的元素为:
    287 12      45      56      67      78      89      99
    288 (10) push_back()方法应用示例完成。
    289 
    290 (11) insert() 方法 :
    291 插入前,vMyInts容器中的元素为:
    292 12      45      56      67      78      89      99
    293 插入后,vMyInts容器中的元素为:
    294 12      11      45      56      67      78      89      99
    295 (11) insert()方法应用示例完成。
    296 
    297 (12) insert() 方法 :
    298 插入前,vMyInts容器中的元素为:
    299 12      11      45      56      67      78      89      99
    300 插入后,vMyInts容器中的元素为:
    301 12      12      12      11      45      56      67      78      89      99
    302 
    303 (12) insert()方法应用示例完成。
    304 
    305 (13) insert() 方法 (容器示例):
    306 插入前,vMyInts容器中的元素为:
    307 12      12      12      11      45      56      67      78      89      99
    308 
    309 插入前,vA1容器中的元素为:
    310 12      23      34
    311 插入后,vMyInts容器中的元素为:
    312 12      12      12      11      45      56      67      78      89      99
    313 
    314 插入后,vA1容器中的元素为:
    315 12      11      45      56      23      34
    316 (13) insert()方法应用示例完成。
    317 
    318 (13) insert() 方法 (数组示例):
    319 插入前,vA1容器中的元素为:
    320 12      11      45      56      23      34
    321 数组中的元素为: {1, 2, 3, 4, 5, 6}
    322 插入后,vA1容器中的元素为:
    323 12      2       3       4       11      45      56      23      34
    324 (13) insert()方法应用示例完成。
    325 
    326 (14) size() 方法:
    327 vA1容器中的元素为:
    328 12      2       3       4       11      45      56      23      34
    329 vA1容器中元素个数为:9
    330 (14) size()方法应用示例完成。
    331 
    332 (15) capacity() 方法:
    333 vA1容器的容量为:9
    334 (15) capacity()方法应用示例完成。
    335 
    336 (16) resize() 方法:
    337 重新分配大小前,vA1容器中元素为:
    338 12      2       3       4       11      45      56      23      34
    339 vA1.resize(6) 重新分配大小后,vA1容器中元素为:
    340 12      2       3       4       11      45
    341 (16) resize()方法应用示例完成。
    342 
    343 (17) resize() 方法:
    344 重新分配大小前,vA1容器中元素为:
    345 12      2       3       4       11      45
    346 vA1.resize(10, 110) 重新分配大小后,vA1容器中元素为:
    347 12      2       3       4       11      45      100     100     100     100
    348 
    349 (17) resize()方法应用示例完成。
    350 
    351 (18) reserve() 方法:
    352 扩容前,vA1容器的容量为:13
    353 扩容后,vA1容器的容量为:30
    354 (18) reserve()方法应用示例完成。
    355 
    356 (19) swap() 方法:
    357 vA1容器中的元素为:
    358 12      2       3       4       11      45      100     100     100     100
    359 
    360 vMyInts容器中的元素为:
    361 12      12      12      11      45      56      67      78      89      99
    362 
    363 vA1容器中的元素为:
    364 12      12      12      11      45
    365 vMyInts容器中的元素为:
    366 12      2       3       4       11
    367 (19) swap() 方法应用示例完成。
    368 
    369 (20) 赋值方法:
    370 vA1容器中的元素为:
    371 12      12      12      11      45
    372  vTemp = vA1 后,vTemp 容器中的元素为:
    373 12      12      12      11      45
    374 (20) 赋值方法应用示例完成。
    375 
    376 (21) 比较操作:
    377 vA1容器中的元素为:
    378 12      12      12      11      45
    379  vTemp 容器中的元素为:
    380 12      12      12      11      45
    381 vA1 == vTemp 比较:1
    382 (21) 比较操作应用示例完成。
    383 */

    类的成员方法应用示例运行结果如下:

    这么多成员方法,为什么没有sort排序方法呢?

    (3)通用成员函数。上面常用方法那么多,怎么没有排序方法呢?这点得追溯于STL的设计理念(尽可能一劳永逸)。

    STL从更广泛的角度定义了非成员函数来执行这些操作,即不是为每个类都定义sort()成员函数,而是定义一个适用于所有容器类的非成员函数sort()。

    试想一个问题,假设有10个类,每个类都支持10种操作,若每个类都有自己的成员函数,则需要定义100(10*10)个成员函数。而采用STL方式,只需要定义10个非成员函数即可。

    另外需要注意,已有执行相同任务的非成员函数,STL有时还会为类定义一个成员函数,因为对于有些操作来说,类特定算法的效率比通用算法高。

    下面学习几个所谓的公用函数:for_each()、random_shuffle()、sort()。

      3.1 for_each函数接受3个参数,前两个是定义容器中区间的迭代器,最后一个是指向函数的指针。可以用for_each函数来代替for循环。例如:

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>   // for_each
     4 using namespace std;
     5 
     6 void printVectorValue(int & rInt)
     7 {
     8     cout << rInt << "	";
     9 }
    10 
    11 void main()
    12 {
    13     cout << "动态构建一个整型容器(请输入整数值,0时退出):
    "; 
    14     vector<int> vMyInts;
    15     int nTemp;
    16     while (cin >> nTemp && nTemp != 0)
    17     {
    18         vMyInts.push_back(nTemp);
    19     }
    20     cout << "您输入 " << vMyInts.size() << " 个元素,分别如下: " << endl;
    21     cout << "使用for循环打印容器元素如下:" << endl;
    22     for (vector<int>::iterator pIt = vMyInts.begin(); pIt != vMyInts.end(); ++pIt)
    23     {
    24         cout << *pIt << "	";
    25     }
    26     cout << endl << "使用for_each打印容器元素如下:" << endl;
    27     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue);
    28     cout << endl << "构建整型容器vMyInts完成" << endl << endl;
    29     cin >> nTemp;
    30 }
    31 // Run out
    32 /*
    33 动态构建一个整型容器(请输入整数值,0时退出):
    34 12
    35 23
    36 34
    37 45
    38 56
    39 67
    40 78
    41 89
    42 90
    43 0
    44 您输入 9 个元素,分别如下:
    45 使用for循环打印容器元素如下:
    46 12      23      34      45      56      67      78      89      90
    47 使用for_each打印容器元素如下:
    48 12      23      34      45      56      67      78      89      90
    49 构建整型容器vMyInts完成
    50 */

      这样可以避免显式使用迭代器变量。

      3.2 random_shffle函数接受两个指定区间的迭代器参数,并随机排列该区间中的元素。应用示例代码如下:

     1 #include <iostream>
     2 #include <vector>
     3 #include <string>
     4 #include <algorithm>   // for_each
     5 using namespace std;
     6 
     7 template<class T>
     8 void printVectorValue(T & rInt)
     9 {
    10     cout << rInt << "	";
    11 }
    12 
    13 void main()
    14 {
    15     cout << "动态构建一个整型容器(请输入整数值,0时退出):
    "; 
    16     vector<int> vMyInts;
    17     int nTemp;
    18     while (cin >> nTemp && nTemp != 0)
    19     {
    20         vMyInts.push_back(nTemp);
    21     }
    22     cout << "您输入 " << vMyInts.size() << " 个元素,分别如下: " << endl;
    23     cout << "使用for_each打印排序前容器元素如下:" << endl;
    24     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
    25     random_shuffle(vMyInts.begin(), vMyInts.end());
    26     cout << endl << "使用for_each打印排序后容器元素如下:" << endl;
    27     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
    28 
    29     cout << endl;
    30     vector<string> vStr;
    31     vStr.push_back("sun");
    32     vStr.push_back("zhang");
    33     vStr.push_back("huang");
    34     vStr.push_back("liu");
    35     vStr.push_back("qin");
    36     cout << endl << "打印排序前容器元素如下:" << endl;
    37     for (int j = 0; j < vStr.size(); ++j)
    38     {
    39         cout << vStr[j].c_str() << "	";
    40     }
    41     std::random_shuffle(vStr.begin(), vStr.end()); // 迭代器
    42     cout << endl << "打印排序后容器元素如下:" << endl;
    43     for (int j = 0; j < vStr.size(); ++j)
    44     {
    45         cout << vStr[j].c_str() << "	";
    46     }
    47     cout << endl;
    48     system("pause");
    49 }

      程序运行结果如下:

      3.3 sort函数也要求容器支持随机访问,该函数有两个版本:

      第一个版本接受两个定义区间的迭代器参数,并使用为存储在容器中的类型元素定义的<运算符。

      备注:如果元素为用户自定义类型,必须定义能够处理该类型对象的operator<()函数),对区间中的元素进行操作。

      第二个版本接受3个参数,前两个参数也是指定区间的迭代器,最后一个参数是指向要使用的函数的指针(而不是比较的operator<()运算符)。

      sort函数的应用示例代码如下:

     1 #include <iostream>
     2 #include <vector>
     3 #include <string>
     4 #include <algorithm>   // for_each
     5 using namespace std;
     6 
     7 template<class T>
     8 void printVectorValue(T & rInt)
     9 {
    10     cout << rInt << "	";
    11 }
    12 
    13 struct student
    14 {
    15     string strName;
    16     int nAge;
    17 
    18     student(string sName = "liu", int nAge = 22) : strName(sName), nAge(nAge)
    19     {}
    20 };
    21 
    22 bool worseThan(const student & stuObject1, const student & stuObject2)
    23 {
    24     if (stuObject1.nAge > stuObject2.nAge)
    25     {
    26         return true;
    27     }
    28     else if (stuObject1.nAge == stuObject2.nAge 
    29         && stuObject1.strName > stuObject2.strName)
    30     {
    31         return true;
    32     }
    33     else
    34     {
    35         return false;
    36     }
    37 }
    38 
    39 void printValue(const student & rStuObject)
    40 {
    41     cout << rStuObject.strName << "  " << rStuObject.nAge << "
    ";
    42 }
    43 
    44 void main()
    45 {
    46     cout << "sort函数版本1测试程序:" << endl;
    47     cout << "动态构建一个整型容器(请输入整数值,0时退出):
    "; 
    48     vector<int> vMyInts;
    49     int nTemp;
    50     while (cin >> nTemp && nTemp != 0)
    51     {
    52         vMyInts.push_back(nTemp);
    53     }
    54     cout << "您输入 " << vMyInts.size() << " 个元素,分别如下: " << endl;
    55     cout << "使用for_each打印排序前容器元素如下:" << endl;
    56     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
    57     sort(vMyInts.begin(), vMyInts.end());  // 版本1
    58     cout << endl << "使用for_each打印排序后容器元素如下:" << endl;
    59     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
    60 
    61     cout << endl << endl << "sort函数版本2测试程序:" << endl;
    62     vector<student> vStudents;
    63     vStudents.push_back(student("sun", 23));
    64     vStudents.push_back(student("zhang", 24));
    65     vStudents.push_back(student("huang", 22));
    66     vStudents.push_back(student("liu", 21));
    67     vStudents.push_back(student("qin", 22));
    68     cout << "使用for_each打印排序前容器元素如下:" << endl;
    69     for_each(vStudents.begin(), vStudents.end(), printValue);
    70     sort(vStudents.begin(), vStudents.end(), worseThan);  // 版本2
    71     cout << "使用for_each打印排序后容器元素如下:" << endl;
    72     for_each(vStudents.begin(), vStudents.end(), printValue);
    73     cout << endl;
    74     system("pause");
    75 }

      程序运行结果如下:

      通用非成员函数结束。

    【3】学习《STL源码剖析》中vector

      (1)vector容器可以自动扩充内存空间,具体的扩充规则测试代码如下:

     1 #include <vector>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 template<class T>
     7 void printVectorValue(T & rInt)
     8 {
     9     cout << rInt << "  ";
    10 }
    11 
    12 template<class T>
    13 void printSizeAndCapacity(vector<T> & oVec)
    14 {
    15     for_each(oVec.begin(), oVec.end(), printVectorValue<T>);
    16     cout << endl << "size = " << oVec.size() << endl;
    17     cout << "capacity = " << oVec.capacity() << endl << endl;
    18 }
    19 
    20 int main()
    21 {
    22     vector<int> iv(2, 9);
    23     printSizeAndCapacity(iv);
    24     for (int i = 0; i < 8; ++i)
    25     {
    26         iv.push_back(i + 1);
    27         printSizeAndCapacity<int>(iv);
    28     }
    29 
    30     system("pause");
    31 }

      vector容器示意图如下:

      运行结果如下:

      有一个遗留问题:如size不为零时,扩充后容量应该是之前的2倍,根据上例实际情况,不应该有奇数值的容量!求再探索,作此备录。

      (2)vector迭代器和数据结构,如下图所示:

      (3)vector部分源码如下:

      1 #include<iostream>
      2 #include<memory.h>
      3 using namespace std;
      4 
      5 // alloc是SGI STL的空间配置器
      6 template <class T, class Alloc = alloc>
      7 class vector
      8 {
      9 public:
     10     // vector的嵌套类型定义,typedefs用于提供iterator_traits<I>支持
     11     typedef T value_type;
     12     typedef value_type* pointer;
     13     typedef value_type* iterator;
     14     typedef value_type& reference;
     15     typedef size_t size_type;
     16     typedef ptrdiff_t difference_type;
     17 protected:
     18     // 这个提供STL标准的allocator接口
     19     typedef simple_alloc <value_type, Alloc> data_allocator;
     20 
     21     iterator start;               // 表示目前使用空间的头
     22     iterator finish;              // 表示目前使用空间的尾
     23     iterator end_of_storage;      // 表示实际分配内存空间的尾
     24 
     25     void insert_aux(iterator position, const T& x); // 在position位置插入值为x的元素
     26 
     27     // 释放分配的内存空间
     28     void deallocate()
     29     {
     30         // 由于使用data_allocator进行内存空间的分配,
     31         // 所以匹配使用data_allocator::deallocate()进行释放
     32         // 如果直接释放, 对于data_allocator内部使用内存池的版本就会发生错误
     33         if (start)
     34             data_allocator::deallocate(start, end_of_storage - start);
     35     }
     36 
     37     void fill_initialize(size_type n, const T& value)
     38     {
     39         start = allocate_and_fill(n, value);
     40         finish = start + n;  // 设置当前使用内存空间的结束点
     41         // 构造阶段(不多分配内存)
     42         // 所以要设置内存空间结束点(与已经使用的内存空间结束点相同)
     43         end_of_storage = finish;
     44     }
     45 
     46 public:
     47     // 获取几种迭代器
     48     iterator begin() { return start; }
     49     iterator end() { return finish; }
     50 
     51     // 返回当前对象个数
     52     size_type size() const { return size_type(end() - begin()); }
     53     size_type max_size() const { return size_type(-1) / sizeof(T); }
     54     // 返回重新分配内存前最多能存储的对象个数
     55     size_type capacity() const { return size_type(end_of_storage - begin()); }
     56     // 判空
     57     bool empty() const { return begin() == end(); }
     58     // 重载[](下标访问)
     59     reference operator[](size_type n) { return *(begin() + n); }
     60 
     61     // 默认构造函数。默认构造vector不分配内存空间
     62     vector() : start(0), finish(0), end_of_storage(0) {}
     63 
     64     vector(size_type n, const T& value) { fill_initialize(n, value); }
     65     vector(int n, const T& value) { fill_initialize(n, value); }
     66     vector(long n, const T& value) { fill_initialize(n, value); }
     67 
     68     // 需要对象提供默认构造函数
     69     explicit vector(size_type n) { fill_initialize(n, T()); }
     70 
     71     vector(const vector<T, Alloc>& x)
     72     {
     73         start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
     74         finish = start + (x.end() - x.begin());
     75         end_of_storage = finish;
     76     }
     77 
     78     ~vector()
     79     {
     80         // 析构对象
     81         destroy(start, finish);
     82         // 释放内存
     83         deallocate();
     84     }
     85 
     86     vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
     87 
     88     // 提供访问函数
     89     reference front() { return *begin(); }
     90     reference back() { return *(end() - 1); }
     91 
     92     ////////////////////////////////////////////////////////////////////////////////
     93     // 向容器尾追加一个元素, 可能导致内存重新分配(开辟新空间、移动原数据、释放原内存)
     94     ////////////////////////////////////////////////////////////////////////////////
     95     //                          push_back(const T& x)
     96     //                                   |
     97     //                                   |---------------- 容量已满?
     98     //                                   |
     99     //               ----------------------------
    100     //           No  |                          |  Yes
    101     //               |                          |
    102     //               ↓                          ↓
    103     //      construct(finish, x);       insert_aux(end(), x);
    104     //      ++finish;                           |
    105     //                                          |------ 内存不足, 重新分配
    106     //                                          |       大小为原来的2倍
    107     //      new_finish = data_allocator::allocate(len);       <stl_alloc.h>
    108     //      uninitialized_copy(start, position, new_start);   <stl_uninitialized.h>
    109     //      construct(new_finish, x);                         <stl_construct.h>
    110     //      ++new_finish;
    111     //      uninitialized_copy(position, finish, new_finish); <stl_uninitialized.h>
    112     ////////////////////////////////////////////////////////////////////////////////
    113 
    114     void push_back(const T& x)
    115     {
    116         // 内存满足条件则直接追加元素, 否则需要重新分配内存空间
    117         if (finish != end_of_storage)
    118         {
    119             construct(finish, x);
    120             ++finish;
    121         }
    122         else
    123             insert_aux(end(), x);
    124     }
    125 
    126 
    127     ////////////////////////////////////////////////////////////////////////////////
    128     // 在指定位置插入元素
    129     ////////////////////////////////////////////////////////////////////////////////
    130     //                   insert(iterator position, const T& x)
    131     //                                   |
    132     //                                   |------------ 容量是否足够 && 是否是end()?
    133     //                                   |
    134     //               -------------------------------------------
    135     //            No |                                         | Yes
    136     //               |                                         |
    137     //               ↓                                         ↓
    138     //    insert_aux(position, x);                  construct(finish, x);
    139     //               |                              ++finish;
    140     //               |-------- 容量是否够用?
    141     //               |
    142     //        --------------------------------------------------
    143     //    Yes |                                                | No
    144     //        |                                                |
    145     //        ↓                                               |
    146     // construct(finish, *(finish - 1));                       |
    147     // ++finish;                                               |
    148     // T x_copy = x;                                           |
    149     // copy_backward(position, finish - 2, finish - 1);        |
    150     // *position = x_copy;                                     |
    151     //152     // data_allocator::allocate(len);                       <stl_alloc.h>
    153     // uninitialized_copy(start, position, new_start);      <stl_uninitialized.h>
    154     // construct(new_finish, x);                            <stl_construct.h>
    155     // ++new_finish;
    156     // uninitialized_copy(position, finish, new_finish);    <stl_uninitialized.h>
    157     // destroy(begin(), end());                             <stl_construct.h>
    158     // deallocate();
    159     ////////////////////////////////////////////////////////////////////////////////
    160 
    161     iterator insert(iterator position, const T& x)
    162     {
    163         size_type n = position - begin();
    164         if (finish != end_of_storage && position == end())
    165         {
    166             construct(finish, x);
    167             ++finish;
    168         }
    169         else
    170             insert_aux(position, x);
    171         return begin() + n;
    172     }
    173 
    174     iterator insert(iterator position) { return insert(position, T()); }
    175 
    176     void pop_back()
    177     {
    178         --finish;
    179         destroy(finish);
    180     }
    181 
    182     iterator erase(iterator position)
    183     {
    184         if (position + 1 != end())
    185             copy(position + 1, finish, position);
    186         --finish;
    187         destroy(finish);
    188         return position;
    189     }
    190 
    191 
    192     iterator erase(iterator first, iterator last)
    193     {
    194         iterator i = copy(last, finish, first);
    195         // 析构掉需要析构的元素
    196         destroy(i, finish);
    197         finish = finish - (last - first);
    198         return first;
    199     }
    200 
    201     // 调整size, 但是并不会重新分配内存空间
    202     void resize(size_type new_size, const T& x)
    203     {
    204         if (new_size < size())
    205             erase(begin() + new_size, end());
    206         else
    207             insert(end(), new_size - size(), x);
    208     }
    209     void resize(size_type new_size) { resize(new_size, T()); }
    210 
    211     void clear() { erase(begin(), end()); }
    212 
    213 protected:
    214     // 分配空间, 并且复制对象到分配的空间处
    215     iterator allocate_and_fill(size_type n, const T& x)
    216     {
    217         iterator result = data_allocator::allocate(n);
    218         uninitialized_fill_n(result, n, x);
    219         return result;
    220     }
    221 
    222     // 提供插入操作
    223     ////////////////////////////////////////////////////////////////////////////////
    224     //                 insert_aux(iterator position, const T& x)
    225     //                                   |
    226     //                                   |---------------- 容量是否足够?
    227     //228     //              -----------------------------------------
    229     //        Yes   |                                       | No
    230     //              |                                       |
    231     //              ↓                                      |
    232     // 从opsition开始, 整体向后移动一个位置                 |
    233     // construct(finish, *(finish - 1));                    |
    234     // ++finish;                                            |
    235     // T x_copy = x;                                        |
    236     // copy_backward(position, finish - 2, finish - 1);     |
    237     // *position = x_copy;                                  |
    238     //239     //                            data_allocator::allocate(len);
    240     //                            uninitialized_copy(start, position, new_start);
    241     //                            construct(new_finish, x);
    242     //                            ++new_finish;
    243     //                            uninitialized_copy(position, finish, new_finish);
    244     //                            destroy(begin(), end());
    245     //                            deallocate();
    246     ////////////////////////////////////////////////////////////////////////////////
    247 
    248     template <class T, class Alloc>
    249     void insert_aux(iterator position, const T& x)
    250     {
    251         if (finish != end_of_storage)    // 还有备用空间
    252         {
    253             // 在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值
    254             construct(finish, *(finish - 1));
    255             ++finish;
    256             T x_copy = x;
    257             copy_backward(position, finish - 2, finish - 1);
    258             *position = x_copy;
    259         }
    260         else   // 已无备用空间
    261         {
    262             const size_type old_size = size();
    263             const size_type len = old_size != 0 ? 2 * old_size : 1;
    264             // 以上配置元素:如果大小为0,则配置1(个元素大小)
    265             // 如果大小不为0,则配置原来大小的两倍
    266             // 前半段用来放置原数据,后半段准备用来放置新数据
    267 
    268             iterator new_start = data_allocator::allocate(len);  // 实际配置
    269             iterator new_finish = new_start;
    270             // 将内存重新配置
    271             try
    272             {
    273                 // 将原vector的安插点以前的内容拷贝到新vector
    274                 new_finish = uninitialized_copy(start, position, new_start);
    275                 // 为新元素设定初值 x
    276                 construct(new_finish, x);
    277                 // 调整水位
    278                 ++new_finish;
    279                 // 将安插点以后的原内容也拷贝过来
    280                 new_finish = uninitialized_copy(position, finish, new_finish);
    281             }
    282             catch(...)
    283             {
    284                 // 回滚操作
    285                 destroy(new_start, new_finish);
    286                 data_allocator::deallocate(new_start, len);
    287                 throw;
    288             }
    289             // 析构并释放原vector
    290             destroy(begin(), end());
    291             deallocate();
    292 
    293             // 调整迭代器,指向新vector
    294             start = new_start;
    295             finish = new_finish;
    296             end_of_storage = new_start + len;
    297         }
    298     }
    299 
    300     ////////////////////////////////////////////////////////////////////////////////
    301     // 在指定位置开始连续插入n个值为x的元素
    302     ////////////////////////////////////////////////////////////////////////////////
    303     //             insert(iterator position, size_type n, const T& x)
    304     //                                   |
    305     //                                   |---------------- 插入元素个数是否为0?
    306     //307     //              -----------------------------------------
    308     //        No    |                                       | Yes
    309     //              |                                       |
    310     //              |                                       ↓
    311     //              |                                    return;
    312     //              |----------- 内存是否足够?
    313     //              |
    314     //      -------------------------------------------------
    315     //  Yes |                                               | No
    316     //      |                                               |
    317     //      |------ (finish - position) > n?                |
    318     //      |       分别调整指针                            |
    319     //      ↓                                              |
    320     //    ----------------------------                      |
    321     // No |                          | Yes                  |
    322     //    |                          |                      |
    323     //    ↓                         ↓                    |
    324     // 插入操作, 调整指针           插入操作, 调整指针      |
    325     //326     //            data_allocator::allocate(len);
    327     //            new_finish = uninitialized_copy(start, position, new_start);
    328     //            new_finish = uninitialized_fill_n(new_finish, n, x);
    329     //            new_finish = uninitialized_copy(position, finish, new_finish);
    330     //            destroy(start, finish);
    331     //            deallocate();
    332     ////////////////////////////////////////////////////////////////////////////////
    333 
    334     template <class T, class Alloc>
    335     void insert(iterator position, size_type n, const T& x)
    336     {
    337         // 如果n为0,则不进行任何操作
    338         if (n != 0)
    339         {
    340             if (size_type(end_of_storage - finish) >= n)
    341             {      // 剩下的备用空间大于等于“新增元素的个数”
    342                 T x_copy = x;
    343                 // 以下计算插入点之后的现有元素个数
    344                 const size_type elems_after = finish - position;
    345                 iterator old_finish = finish;
    346                 if (elems_after > n)
    347                 {
    348                     // 插入点之后的现有元素个数 大于 新增元素个数
    349                     uninitialized_copy(finish - n, finish, finish);
    350                     finish += n;    // 将vector 尾端标记后移
    351                     copy_backward(position, old_finish - n, old_finish);
    352                     fill(position, position + n, x_copy); // 从插入点开始填入新值
    353                 }
    354                 else
    355                 {
    356                     // 插入点之后的现有元素个数 小于等于 新增元素个数
    357                     uninitialized_fill_n(finish, n - elems_after, x_copy);
    358                     finish += n - elems_after;
    359                     uninitialized_copy(position, old_finish, finish);
    360                     finish += elems_after;
    361                     fill(position, old_finish, x_copy);
    362                 }
    363             }
    364             else
    365             {   // 剩下的备用空间小于“新增元素个数”(那就必须配置额外的内存)
    366                 // 首先决定新长度:就长度的两倍 , 或旧长度+新增元素个数
    367                 const size_type old_size = size();
    368                 const size_type len = old_size + max(old_size, n);
    369                 // 以下配置新的vector空间
    370                 iterator new_start = data_allocator::allocate(len);
    371                 iterator new_finish = new_start;
    372                 __STL_TRY
    373                 {
    374                     // 以下首先将旧的vector的插入点之前的元素复制到新空间
    375                     new_finish = uninitialized_copy(start, position, new_start);
    376                     // 以下再将新增元素(初值皆为n)填入新空间
    377                     new_finish = uninitialized_fill_n(new_finish, n, x);
    378                     // 以下再将旧vector的插入点之后的元素复制到新空间
    379                     new_finish = uninitialized_copy(position, finish, new_finish);
    380                 }
    381 #         ifdef  __STL_USE_EXCEPTIONS
    382                 catch(...)
    383                 {
    384                     destroy(new_start, new_finish);
    385                     data_allocator::deallocate(new_start, len);
    386                     throw;
    387                 }
    388 #         endif /* __STL_USE_EXCEPTIONS */
    389                 destroy(start, finish);
    390                 deallocate();
    391                 start = new_start;
    392                 finish = new_finish;
    393                 end_of_storage = new_start + len;
    394             }
    395         }
    396     }
    397 };

      (4)使用主要问题及成员函数详解。

        4.1 erase函数。vector::erase()方法有两种重载形式:

          (1.1)iterator erase (iterator _Where);

          (1.2)iterator erase (iterator _First, iterator _Last);

          如果是删除指定位置的元素时:返回值是一个迭代器,指向删除元素下一个元素。

          如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素。

          请看如下“临床典型性”应用错误示例代码:

     1 #include <vector> 
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 template<class T>
     7 void printVectorValue(T & rInt)
     8 {
     9     cout << rInt << "  ";
    10 }
    11 
    12 void main() 
    13 { 
    14     vector <int> v1;
    15     for (int i = 0; i < 6; ++i)
    16     {
    17         v1.push_back(i + 10);
    18     }
    19     cout << "(1) v1 容器元素如下:" << endl;
    20     for_each(v1.begin(), v1.end(), printVectorValue<int>);
    21     cout << endl;
    22 
    23     v1.erase(v1.begin( ));
    24     cout << "(2) v1 容器元素如下:" << endl;
    25     for_each(v1.begin(), v1.end(), printVectorValue<int>);
    26     cout << endl;
    27 
    28     v1.erase(v1.begin( ) + 1, v1.begin( ) + 3);
    29     cout << "(3) v1 容器元素如下:" << endl;
    30     for_each(v1.begin(), v1.end(), printVectorValue<int>);
    31     cout << endl;
    32 
    33     v1.push_back(14);
    34     vector<int>::iterator itPt;
    35     for (itPt = v1.begin(); itPt != v1.end(); ++itPt) 
    36     { 
    37         if (14 == *itPt) 
    38         { 
    39             v1.erase(itPt);
    40         } 
    41     }
    42 
    43     system("pause");
    44 }

          程序运行结果如下:

          分析程序:一一遍历容器找到元素值为14,然后一一删除。程序为什么会崩溃呢?

          其实,出现这种原因是没搞懂erase的删除原理(套路),当调用erase()后迭代器就失效了,即变成一个野指针。

          所以要处理这种问题,关键是要解决调用erase()方法后,迭代器变成野指针的问题。

          结合套路,解决这个问题有两种方案:

          第一种:正向删除。

          第二种:逆向删除。代码如下:

      1 #include <vector> 
      2 #include <iostream>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 template<class T>
      7 void printVectorValue(T & rInt)
      8 {
      9     cout << rInt << "  ";
     10 }
     11 
     12 // 正删
     13 template<class T>
     14 void eraseAll(vector<T> & v1, T value)
     15 {
     16     vector<T>::iterator itPt;
     17     for (itPt = v1.begin(); itPt != v1.end();) 
     18     { 
     19         if (value == *itPt) 
     20         { 
     21             itPt = v1.erase(itPt);
     22         }
     23         else
     24         {
     25             ++itPt;
     26         }
     27     }
     28 }
     29 
     30 // 逆删
     31 template<class T>
     32 void eraseAll2(vector<T> & v1, T value)
     33 {
     34     vector<T>::iterator itPt;
     35     for (itPt = --v1.end(); itPt != v1.begin();) 
     36     { 
     37         if (value == *itPt) 
     38         { 
     39             v1.erase(itPt--);
     40         }
     41         else
     42         {
     43             --itPt;
     44         }
     45     }
     46 
     47     if (value == *itPt)
     48     {
     49         v1.erase(itPt);
     50     }
     51 }
     52 
     53 void main() 
     54 { 
     55     vector<int> v1(6, 9);
     56     for (int i = 0; i < 6; ++i)
     57     {
     58         v1.push_back(i + 10);
     59     }
     60     cout << "(1) v1 容器元素如下:" << endl;
     61     for_each(v1.begin(), v1.end(), printVectorValue<int>);
     62     cout << endl;
     63 
     64     v1.erase(v1.begin( ));
     65     cout << "(2) v1 容器元素如下:" << endl;
     66     for_each(v1.begin(), v1.end(), printVectorValue<int>);
     67     cout << endl;
     68 
     69     v1.erase(v1.begin( ) + 1, v1.begin( ) + 3);
     70     cout << "(3) v1 容器元素如下:" << endl;
     71     for_each(v1.begin(), v1.end(), printVectorValue<int>);
     72     cout << endl;
     73 
     74     v1.insert(v1.begin() + 5, 3, 12);
     75     v1.push_back(15);
     76     v1.push_back(15);
     77     cout << "(4) 删除前 v1 容器元素如下:" << endl;
     78     for_each(v1.begin(), v1.end(), printVectorValue<int>);
     79     cout << endl;
     80 
     81 // 第一种正向删除
     82     eraseAll<int>(v1, 9);
     83     eraseAll<int>(v1, 12);
     84     eraseAll<int>(v1, 15);
     85 
     86 /* 第二种逆向删除
     87     eraseAll2<int>(v1, 9);
     88     eraseAll2<int>(v1, 12);
     89     eraseAll2<int>(v1, 15);
     90 */
     91     cout << "(5) 删除9,12,15后 v1 容器元素如下:" << endl;
     92     for_each(v1.begin(), v1.end(), printVectorValue<int>);
     93     cout << endl;
     94     /* 错误删除!!
     95     for (itPt = v1.begin(); itPt != v1.end(); ++itPt) 
     96     { 
     97         if (14 == *itPt) 
     98         { 
     99             v1.erase(itPt);
    100         } 
    101     }
    102     */
    103 
    104     system("pause");
    105 }
    106 
    107 // Run out
    108 /*
    109 (1) v1 容器元素如下:
    110 9  9  9  9  9  9  10  11  12  13  14  15
    111 (2) v1 容器元素如下:
    112 9  9  9  9  9  10  11  12  13  14  15
    113 (3) v1 容器元素如下:
    114 9  9  9  10  11  12  13  14  15
    115 (4) 删除前 v1 容器元素如下:
    116 9  9  9  10  11  12  12  12  12  13  14  15  15  15
    117 (5) 删除9,12,15后 v1 容器元素如下:
    118 10  11  13  14
    119 请按任意键继续. . .
    120 */

          规避开失效指针,完全可以正常删除。

        4.2 insert函数

        insert函数源码如下:

        insert函数两种情况分析如下:

        insert函数重载多,使用比较方便。

    【4】vector总结

      相比C++内置的array数组类,vector模板类是有生命的、动态的、可塑性的数组,使用更方便,更健壮。

    Good  Good  Study, Day  Day  Up.

    顺序  选择  循环  总结

  • 相关阅读:
    关于SQL优化(转载,格式有调整)
    开篇(我想有个家,安稳的家)
    常见兼容问题
    BFC概念及应用
    浏览器私有前缀及内核
    css3新增属性
    宽高自适应
    css布局
    css3选择器
    常用标签
  • 原文地址:https://www.cnblogs.com/Braveliu/p/6264543.html
Copyright © 2020-2023  润新知