zoukankan      html  css  js  c++  java
  • c++基础(三)——容器

    1. 顺序容器

    • vector和string将元素保存在连续的内存空间中。由于元素是连续存储的,由元素的下标来计算其地址是非常快速的。但是在这两种容器的中间位置添加或删除元素就非常耗时
    • list和forward_list两个容器的设计目的是令容器任何位置的添加和删除操作都很快速。作为代价,这两个容器不支持元素的随机访问
    • deque是一个更为复杂的数据结构。与string和vector类似,deque支持快速的随机访问。在deque的中间位置添加或删除元素的代价(可能)很高。但是,在deque的两端添加或删除元素都是很快的,与list和forward_list添加删除元素的速度相当
    • forward_list没有size操作

    1.1 容器的定义和初始化

      每个容器类型都定义了一个默认构造函数。除array之外,其他容器的默认构造函数都会创建一个指定类型的空容器,且都可以接受指定容器大小和元素初始值的参数。

      

     

    1.1.1 将一个容器初始化为另一个容器的拷贝

      主要有两种方式,①直接拷贝整个容器,②(array除外)拷贝由一个迭代器对指定的元素的范围。

     1 #include<vector>
     2 #include<string>
     3 #include<deque>
     4 #include<forward_list>
     5 #include<list>
     6 #include<iostream>
     7 using namespace std;
     8 
     9 int main() {
    10     list<string> authors = { "tom", "Mike", "Bob" };
    11     vector<const char*> articles = { "ad", "mi" ,"po" };
    12 
    13     list<string> authors2(authors);
    14     //vector<string> articles2(articles);//错误,类型不一致
    15 
    16     /*forward_list 
    17         单向list,不能反向迭代(list可以)
    18         不能使用size函数,但是可以使用迭代器的distance来计算    
    19       但是
    20       forward_list的操作比list容器块,且内存占用少
    21     */
    22 
    23     forward_list<string> articles3(articles.begin(), articles.end());
    24     cout << distance(articles3.begin(), articles3.end()) << endl;   // 3d
    25 
    26     getchar();
    27     return 0;
    28 }

    1.1.2 与顺序容器大小相关的构造函数

      只有顺序容器的构造函数才接受大小参数,关联容器不支持。

    1 vector<int> ivec (10, -1);    //10个int元素,每个都初始化为-1
    2 list<string> svec(10,"hi");    //10个string,每个够初始化为“hi"
    3 forward_list<int> ivec(10);    //10个元素,每个都初始化为0
    4 deque<string> svec(10);    //10个元素,每个都是空string

    1.1.3 标准库array具有固定大小

      array 是提供的新容器,比内置数组更安全。两者一定区别如下:

     1 // 内置数组初始化
     2 int a[5];
     3 int b[] = { 1,2,3 };
     4 int c[5] = { 1,2,3 };//其他值默认初始化 0 
     5 // 访问数组下标时,可以非 size_type 类型,只要不越界。但是容器不行 
     6 int *ptr = &a[5];
     7 cout << ptr[-3] << endl;
     8 
     9 // 数组容器
    10 array<int, 5> a1;
    11 array<int, 5> b1 = { 1,2,3, };
    12 // 但是容器能拷贝复制,只要容器 类型+大小 一致
    13 array<int, 5> c1 = b1;
    14 //a1 = b1;  //但是不能直接拷贝
    15 // 容器的遍历遵循普通容器遍历方式

    1.2 顺序容器操作

    1.2.1 向顺序容器添加元素

    • push_back : 除了array 和 forward_list 之外,每个顺序容器(包括string 类型),都支持
    • 除了push_back之外,listforward_listdeque 还支持名为 push_front 的操作
    • 在容器特定位置添加元素

      vecotr,deque,list,string 支持 insert(iter, value) 的操作(forward_list 有自己的 insert 的操作),所以,即使 vector 没有 push_front 操作,但是可:

    1 vector<string> vct;
    2 vct.insert(vct.begin(), "test");  // vector 不插入末尾,则效率很慢
    • 插入范围元素:
    // 接受一个元素数目和元素值
    vct.insert(vct.end(), 4, "qaq"); //在end处插入,个数为4,初始化为qaq的字符串
    
    // 接受一对迭代器
    vct.insert(vct.end(), vct2.end() - 2, vct2.end());//插入位置,vct2给定范围
    
    // 接受位置和列表
    vct.insert(vct.end(), { "2333", "xswl" });

    // 插入的列表不能指向目标容器
    // vct.insert(vct.end(), vct.begin(), vct.end()); // 错误
    • 使用 insert 的返回值。insert 返回值为指向这个新元素
    1 list<string> lst;
    2 auto iter = lst.begin();
    3 while (cin >> word)
    4     iter = lst.insert(iter, word);    //等价于调用push_front
    • emplace
    1 //在c的末尾构造一个Sales_data对象
    2 //使用三个参数的Sales_data构造函数
    3 c.emplace_back("978-9897897987", 25, 15.99);
    4 //错误:没有接受三个参数的push_back版本
    5 c.push_back("978-9897897987", 25, 15.99);
    6 //正确:创建一个临时的Sales_data对象传递给push_back
    7 c.push_back(Sales_data("978-9897897987", 25, 15.99));

    1.2.2 访问元素

     包括 array 在内的每个顺序容器中,都有一个 front 成员函数,而除 forward_list 之外,所有顺序容器都有 back 成员函数。 

    1 // 解引用一个迭代器时,要判空
    2     if (!lst.empty()) {
    3         auto val1 = *lst.begin(), val2 = lst.front();
    4 
    5         auto last = lst.end();
    6         auto val3 = *(--last);// forward_list 迭代器不能递减
    7         auto val4 = lst.back();// forward_list 不支持
    8     }

      下面再看:

     1 /*
     2     front back 都是返回引用
     3 */
     4  
     5 int main() {
     6 
     7     // 数组容器
     8     array<int, 5> a1;
     9     array<int, 5> b1 = { 1,2,3, };
    10 
    11     b1.front() = 9; // b1 初始值改变
    12     int &c = b1.back();
    13     c = 99;  // b1 末尾值改变
    14 
    15     // auto 会吃引用
    16     auto a2 = a1.front();
    17     a2 = 999; // 无效,可通过 auto &a2 
    18 
    19     getchar();
    20     return 0;
    21 }

    1.2.3 删除元素

      vector 和 string 不支持 push_front 所以不支持 pop_front。同时 vct.clear() 等同于 vct.erase(vct.begin(), vct.end())。

      

    1.2.4 删除插入更新迭代器

      insert 之后返回的是新插入的元素的迭代器,erase之后返回的是被删除的后一个元素的迭代器(此时注意end)。

     1 int main() {
     2     // 删除所有偶数元素,复制所有奇数元素
     3     vector<int> v = { 0,1,2,3,4,5,6,7,8,9 };
     4     auto iter = v.begin();
     5 
     6     while (iter != v.end()) {
     7         if (*iter % 2) {
     8             iter = v.insert(iter, *iter);
     9             iter += 2;
    10         }
    11         else {
    12             iter = v.erase(iter);
    13         }
    14     }
    15 
    16     getchar();
    17     return 0;
    18 }

      不要保存容器的end迭代器,当容器增加或者删除元素时,end迭代器也会失效,所以应该通过 v.end() 来判断,而不应保存至某一个局部变量。

      

    1.2.5 构造 string 的其他方法

      

     1  
     2 int main() {
     3     char ch[] = { 'a','b','c','1','2' };//不空字符结尾
     4     string s(ch, 5);
     5     cout << s << endl; //abc12
     6 
     7     string s2(s, 1); // (string,pos) 从pos位置开始拷贝
     8     cout << s2 << endl;// bc12
     9 
    10     string s3(s, 1, 2); // (string,start,length)
    11     cout << s3 << endl; // bc
    12 
    13     /*
    14     通常当我们从一个 const char* 创建 string 时,指针指向的数组必须以空字符('/0')结尾,拷贝
    15     操作遇到空字符时停止。
    16     如果我们传递给构造函数拷贝长度,则无所谓
    17     */
    18     const char *cc = "qaq23333";//以空字符结尾
    19     string s4(cc);
    20     string s5(ch); // ch 不是以空字符结尾,即未定义
    21 
    22     cout << s4 << "	" << s5 << endl;//打印s5出现奇怪字符
    23 
    24 
    25     getchar();
    26     return 0;
    27 }

    1.2.6 string操作——substr,insert,erase

     1 #define Log(s) cout << s << endl;
     2 int main() {
     3     
     4     string str("233qaq");
     5     
     6     /// substr
     7     string s2 = str.substr(2);
     8     Log(s2); // 3qaq
     9     s2 = str.substr(0, 2);
    10     Log(s2);//23
    11 
    12     /// insert
    13     str.insert(2, s2); // 下表版本插入
    14     Log(str); //23233qaq
    15     str.insert(str.end(), 'h');// 迭代器版本插入
    16     Log(str); //23233qaqh
    17     str.insert(0, s2, 1, 1);// 插入3
    18     Log(str); //33233qaqh
    19     str.insert(0, "hi");
    20     Log(str); //hi33233qaqh
    21 
    22     ///  erase
    23     string str("This is an example sentence.");
    24     str.erase(10, 8);        // 从下标10开始,erase 8位            
    25     Log(str); // "This is an sentence."
    26     str.erase(str.begin() + 9);   // begin迭代器开始第九位
    27     Log(str); // "This is a sentence."
    28     str.erase(str.begin() + 5, str.end() - 9); 
    29     Log(str)// "This sentence."
    30     
    31 
    32 
    33     getchar();
    34     return 0;
    35 }

    1.2.7 string操作——append,replace

     1 #define Log(s) cout << s << endl;
     2 int main() {
     3     string s("hello"), s2 = s;
     4     s.insert(s.size(),",world");
     5     s2.append(",world"); // 同上,效果一致
     6     Log(s);
     7     Log(s2);
     8 
     9     s.erase(5, 6); // 从下标5开始,erase 6 位
    10     s.insert(5, ",Bob");
    11     s2.replace(5, 6, ",Bob"); // 效果同上两句话一致
    12     Log(s);
    13     Log(s2);
    14      
    15     getchar();
    16     return 0;
    17 }
  • 相关阅读:
    关于写页面时容易发生的问题
    用wamp实现前端和php的交互效果
    原生封装的ajax
    用angular引入复杂的json文件2
    用angular引入复杂的json文件
    vue属性
    vue的事件
    require'模块化jquery和angular问题
    css3在页面中插入内容
    css3+javascript实现翻页幻灯片
  • 原文地址:https://www.cnblogs.com/KongHuZi/p/11342667.html
Copyright © 2011-2022 走看看