zoukankan      html  css  js  c++  java
  • 『C++』STL容器入门

    最近在学习opencv,因为C++基础很烂,所以遇到了不少问题,其中STL模块也是没少接触,特此简单了解一下STL的容器类型(主要是Vector)和迭代器的简单用法。

    C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。其核心包括以下三个组件:

    组件描述
    容器(Containers) 容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。
    算法(Algorithms) 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
    迭代器(iterators) 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。

    这三个组件都带有丰富的预定义函数,帮助我们通过简单的方式处理复杂的任务。在网上看到一篇很好的入门介绍,特产备份记录以供查阅,如果有读者看到本文建议去原作者处阅读(原文链接)。

    STL内容丰富而强大,本节我们仅仅简单的介绍常用常用的容器,方便查阅,而中最基本以及最常用的类或容器无非就是以下几个:

    • string
    • vector
    • set
    • list
    • map

    下面就依次介绍它们,并给出一些最常见的最实用的使用方法,做到快速入门。

    一、string

    1、初始化

    C语言创建字符串的方法一般如下:

    char* s1 = "Hello SYSU!"; //创建指针指向字符串常量,这段字符串我们是不能修改的
    
    //想要创建 可以修改的字符串,我们可以使用数组分配空间
    char s2[20] = "Hello SYSU!";
    //或者这样
    char s3[] = "Hello SYSU!";
    
    //当然我们也可以动态分配内存
    char* s4 = (char*)malloc(20);
    gets(s4);
    

    C++ 标准库中的string表示可变长的字符串,它在头文件string里面。

    #include <string>
    

    用string初始化字符串分两类:用“=”号就是拷贝初始化,否则就是直接初始化。

    string s1;//初始化字符串,空字符串
    string s2 = s1; //拷贝初始化,深拷贝字符串
    string s3 = "I am Yasuo"; //直接初始化,s3存了字符串
    string s4(10, 'a'); //s4存的字符串是aaaaaaaaaa
    string s5(s4); //拷贝初始化,深拷贝字符串
    string s6("I am Ali"); //直接初始化
    string s7 = string(6, 'c'); //拷贝初始化,cccccc
    

    2、常用操作

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        string s1;//初始化字符串,空字符串
        string s2 = s1; //拷贝初始化,深拷贝字符串
        string s3 = "I am Yasuo"; //直接初始化,s3存了字符串
        string s4(10, 'a'); //s4存的字符串是aaaaaaaaaa
        string s5(s4); //拷贝初始化,深拷贝字符串
        string s6("I am Ali"); //直接初始化
        string s7 = string(6, 'c'); //拷贝初始化,cccccc
    
        //string的各种操作
        string s8 = s3 + s6;//将两个字符串合并成一个
        s3 = s6;//用一个字符串来替代另一个字符串的对用元素
    
        cin >> s1;
    
        cout << s1 << endl;
        cout << s2 << endl;
        cout << s3 << endl;
        cout << s4 << endl;
        cout << s5 << endl;
        cout << s6 << endl;
        cout << s7 << endl;
        cout << s8 << endl;
        cout << "s7 size = " << s7.size() << endl; //字符串长度,不包括结束符
        cout << (s2.empty() ? "This string is empty" : "This string is not empty") << endl;;
    
        system("pause");
        return 0;
    }
    

     

    getline

    我们输入"   123   456"仅仅读取到了"123",这是因为cin不会计算初始的空格,且遇到字符后面的第一个空格就会停止,解决方式为:

    cin>>s1>>s2;
    

    会将"123"分给s1,将"456"分给s2。

    如果不想像上面那样创建多个string来存储单词,那就是用getline来获取一整行内容,

    string str;
    getline(cin, str);
    cout << str << endl;
    

    string加法

    当把string对象和字符面值及字符串面值混在一条语句中使用时,必须确保+的两侧的运算对象至少有一个是string

    string s1 = s2 + ", "; //正确,假定s2为string
    string s3 = "s " + ", "; //错误
    string s4 = "hello" + ", " + s1; //错误
    string s5 = s1 + "hello " + ", "; //改一下顺序,s1放前头,正确了,注意理解=号右边的运算顺序
    

    3、访问string元素

    访问字符串的每个字符,

    for (int i = 0; i < s3.size(); i++)
    {
        cout << s3[i] << endl;
        s3[i] = 's';
    }
    

    迭代器

    在C语言中一般用下标或者指针来访问数组元素,而在C++里,有个新奇的东西叫做迭代器iterator,我们可以使用它来访问容器元素。

    string str("hi sysu");
    for (string::iterator it = str.begin(); it != str.end(); it++)
    {
        cout << *it << endl;
    }
    

    类似常量指针,也可以是使用const_iterator使得访问元素时是能读不能写,

    string str2("hi sysu");
    for (string::const_iterator it = str2.begin(); it != str2.end(); it++)
    {
        cout << *it << endl;
        *it = 'l'; //这是错误的,不能写
    }
    

    4、字符串查找/判断

    string还有一些很好用的函数,比如找子串,

    string sq("heoolo sdaa ss");
    cout << s.find("aa", 0) << endl; //返回的是子串位置。第二个参数是查找的起始位置,如果找不到,就返回string::npos
    if (s.find("aa1", 0) == string::npos)
    {
        cout << "找不到该子串!" << endl;
    }
    

    二、vector

    C++ STL中的verctor好比是C语言中的数组,但是vector又具有数组没有的一些高级功能。要想用vector首先得包含头文件vector。

    #include <vector>
    

    1、初始化

    如果vector的元素类型是int,默认初始化为0;如果vector元素类型为string,则默认初始化为空字符串。

    vector<int> v1;
    vector<float> v2;
    vector<string> v3;
    vector<vector<int> >;  //注意空格。这里相当于二维数组int a[n][n];
    vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括号
    vector<string> v6 = { "hi","my","name","is","lee" };
    vector<int> v7(5, -1); //初始化为-1,-1,-1,-1,-1。第一个参数是数目,第二个参数是要初始化的值
    vector<string> v8(3, "hi");
    vector<int> v9(10); //默认初始化为0
    vector<string> v10(4); //默认初始化为空字符串
    

    2、常用操作

    访问和操作vector中的元素,

    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << endl;
        v1[i] = 100;
        cout << v1[i] << endl;
    }
    

    注意:只能对已存在的元素进行赋值或者修改操作,如果是要加入新元素,务必使用push_back。push_back的作用有两个:告诉编译器为新元素开辟空间、将新元素存入新空间里,添加位置为尾部,

    for (int i = 0; i < 20; i++)
    {
        v1.push_back(i);
    }
    

    比如下面的代码是错误的,但是编译器不会报错,就像是数组越界,

    vector<int> vec;
    vec[0] = 1;  //错误!
    

    迭代器

    vector<string> v6 = { "hi","my","name","is","lee" };
    for (vector<string>::iterator iter = v6.begin(); iter != v6.end(); iter++)
    {
        cout << *iter << endl;
        //下面两种方法都行
        cout << (*iter).empty() << endl;
        cout << iter->empty() << endl; 
    }
    

    上面是正向迭代,也可以反向迭代:

    for (vector<string>::reverse_iterator iter = v6.rbegin(); iter != v6.rend(); iter++)
    {
        cout << *iter << endl;
    }
    

    3、增删查改

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    template <typename T>  
    void showvector(vector<T> v)
    {
        for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
        {
            cout << *it;
        }
        cout << endl;
    }
    
    int main()
    {
        vector<string> v6 = { "hi","my","name","is","lee" };
        v6.resize(3);  //重新调整vector容量大小
        showvector(v6);
    
        vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括号
        cout << v5.front() << endl; //访问第一个元素
        cout << v5.back() << endl; //访问最后一个元素
    
        showvector(v5);
        v5.pop_back(); //删除最后一个元素
        showvector(v5);
        v5.push_back(6); //加入一个元素并把它放在最后
        showvector(v5);
        v5.insert(v5.begin()+1,9); //在第二个位置插入新元素
        showvector(v5);
        v5.erase(v5.begin() + 3);  //删除第四个元素
        showvector(v5);
        v5.insert(v5.begin() + 1, 7,8); //连续插入7个8
        showvector(v5);
        v5.clear(); //清除所有内容
        showvector(v5);
    
        system("pause");
        return 0;
    } 
    

    【注1】但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素!

    【注2】push_back把元素插入容器末尾,insert把元素插入任何你指定的位置,不过push_back速度一般比insert快。如果能用push_back尽量先用push_back。

    【注3】template <typename T>可以根据需要的类型进行匹配,其实就是模板。

    三、set

    set跟vector差不多,它跟vector的唯一区别就是,set里面的元素是有序的且唯一的,只要你往set里添加元素,它就会自动排序,而且,如果你添加的元素set里面本来就存在,那么这次添加操作就不执行。

    要想用set需要头文件set:

    #include <set>
    

    一个使用示范如下:

    #include <iostream>
    #include <set>
    #include <string>
    
    using namespace std;
    
    template <typename T>
    void showset(set<T> v)
    {
        for (set<T>::iterator it = v.begin(); it != v.end(); it++)
        {
            cout << *it;
        }
        cout << endl;
    }
    
    int main()
    {
        set<int> s1{9,8,1,2,3,4,5,5,5,6,7,7 }; //自动排序,从小到大,剔除相同项
        showset(s1);
        set<string> s2{ "hello","sysy","school","hello" }; //字典序排序
        showset(s2);
        s1.insert(9); //有这个值了,do nothing
        showset(s1);
        s2.insert("aaa"); //没有这个字符串,添加并且排序
        showset(s2);
        
        system("pause");
        return 0;
    } 
    

    四、list

    list是一个双向链表,而单链表对应的容器则是foward_list

    list即双向链表的优点是插入和删除元素都比较快捷,缺点是不能随机访问元素。

    要想使用list需要头文件list,

    #include <list>
    

    使用示范如下

    #include <iostream>
    #include <list>
    #include <string>
    
    using namespace std;
    
    template <typename T>
    void showlist(list<T> v)
    {
        for (list<T>::iterator it = v.begin(); it != v.end(); it++)
        {
            cout << *it;
        }
        cout << endl;
    }
    
    int main()
    {
        list<int> l1{ 1,2,3,4,5,5,6,7,7 };
        showlist(l1);
        list<double> l2;
        list<char> l3(10);
        list<int> l4(5, 10); //将元素都初始化为10
        showlist(l4);
    
        
        system("pause");
        return 0;
    } 
    

     

    值得注意的是,list容器不能调用algorithm下的sort函数进行排序,因为sort函数要求容器必须可以随机存储,而list做不到。所以,list自己做了一个自己用的排序函数,用法如下:

    list<int> l1{ 8,5,7,6,1,2,3,4,5,5,6,7,7 };
    l1.sort();
    

    五、map

    map运用了哈希表地址映射的思想,也就是key-value的思想,来实现的。

    首先给出map最好用也最最常用的用法例子,就是用字符串作为key去查询操作对应的value。

    要使用map得先加个头文件map。

    #include <map>
    

    使用示范如下

    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    
    void showmap(map<string, int> v)
    {
        for (map<string, int>::iterator it = v.begin(); it != v.end(); it++)
        {
            cout << it->first << "  " << it->second << endl;  //注意用法,不是用*it来访问了。first表示的是key,second存的是value
        }
        cout << endl;
    }
    
    int main()
    {
        map<string, int> m1; //<>里的第一个参数表示key的类型,第二个参数表示value的类型
        m1["Kobe"] = 100;
        m1["James"] = 99;
        m1["Curry"] = 98;
    
        string s("Jordan");
        m1[s] = 90;
    
        cout << m1["Kobe"] << endl;
        cout << m1["Jordan"] << endl;
        cout << m1["Durant"] << endl; //不存在这个key,就显示0
    
        m1.erase("Curry");//通过关键字来删除
        showmap(m1);
        m1.insert(pair<string, int>("Harris", 89)); //也可以通过insert函数来实现增加元素
        showmap(m1);
        m1.clear(); //清空全部
    
    
        system("pause");
        return 0;
    }
    

    如果想看看某个存不存在某个key,可以用count来判断,

    if (m1.count("Lee"))
    {
        cout << "Lee is in m1!" << endl;
    }
    else
    {
        cout << "Lee do not exist!" << endl;
    }
    

     用迭代器来访问元素

    for (map<string, int>::iterator it = m1.begin(); it != m1.end(); it++)
    {
        cout << it->first<<"  "<<it->second << endl;  //注意用法,不是用*it来访问了。first表示的是key,second存的是value
    }
    
  • 相关阅读:
    洛谷—— P3353 在你窗外闪耀的星星
    洛谷—— P1238 走迷宫
    洛谷—— P1262 间谍网络
    9.8——模拟赛
    洛谷—— P1189 SEARCH
    算法
    May 22nd 2017 Week 21st Monday
    May 21st 2017 Week 21st Sunday
    May 20th 2017 Week 20th Saturday
    May 19th 2017 Week 20th Friday
  • 原文地址:https://www.cnblogs.com/hellcat/p/9878909.html
Copyright © 2011-2022 走看看