C++学习记录———容器的简单整理

1. 容器的概念

容器是用来批量存储数据的集合,数据元素可以是用户自定义类型,也可以是C++预定定义类型。容器类的对象自动申请和释放内存,无需new和delete操作。


容器:顺序容器 和关联容器
顺序容器:元素之间是顺序关系,元素有固定的位置
关联容器:元素之间没有严格物理上的顺序关系。内部是有联系的
顺序容器:Array数组,vector向量,list双向链表,deque
关联容器:map 键值对 ,mulitmap 多重键值对


容器分类如下图所示:

2. 容器的分类

2.1 顺序容器

是一种各个元素直接有顺序关系的线性容器,每个元素都有自己的位置,通过下标或迭代器进行访问,除非删除或者插入的数据改变元素的顺序

本次学习的顺序容器有:array(数组)、string、vector(向量)、list(列表)、deque(队列)

2.1.1 array(数组)

C++11新增的数组,符合容器的设计规范,使用起来更加方便。

关于array的使用

#include <iostream>
#include <array>
using namespace std;

int main()
{
    //创建一个长度为5的int数组
    array<int,5> arr = {1,2,3};
    //取出对应下标的元素值
    cout << arr.at(0) << endl; //1
    cout << arr[1] << endl; //2
    cout << arr[4] << endl; //0

    //更改第四个数据的值为884
    arr[3] = 886;
    cout << arr[3] << endl;

    cout << "-----for------" << endl;
    for(int i = 0; i<arr.size();i++)
    {
        cout << arr.at(i) << " ";
    }
    cout << endl;

    //给所有元素填充一个固定值
    arr.fill(521);


    cout << "-----foreach------" << endl;
    for(int i:arr)
    {
        cout << i << " ";
    }
    cout << endl;

    return 0;
}

2.1.2 string

string是C++源码中自带的类,类可以包含很多成员函数等。

关于string类的函数个人整理后在下面代码中展示:

#include <iostream>

using namespace std;

int main()
{
    //创建一个内容为空的字符串对象
    string s;
    cout << s.empty() << endl; //1

    string s1 = "Monday"; //隐式调用构造函数
    string s2("Monady"); //显示调用构造函数
    cout << (s1==s2) << endl; //0

    string s3(s2); //拷贝构造函数
    s2 = s1; //赋值运算符
    cout << s3 << " " << s2 << endl; //Monady  Monday

    //参数1:char*原字符串 参数2:从前往后保留字符数
    string s4("ASDFF",2);
    cout << s4 << endl; //AS
    //参数1:string原字符串 参数2:从前往后不保留字符数
    string s5(s2,2);
    cout << s5 << endl; //nady

    //参数1:字符数量 参数2:cahr字符内容
    string s6(5,'A');
    cout << s6 << endl; //AAAAA

    //字符串拼接:+
    string s7 = s4 + s6;
    cout << s7 << endl; //ASAAAAA

    //向后追加字符串:append()
    s7.append("YYY").append("WUW");
    cout << s7 << endl; //ASAAAAAYYYWUW

    //向后追加单字符:push_back()
    s7.push_back('p');
    cout << s7 << endl; //ASAAAAAYYYWUWp

    //交换字符串:swap()
    swap(s5,s6);
    cout << s5 << " " << s6 << endl; //AAAAA nday

    //插入字符串:insert() 参数1:插入的位置 参数2:插入的内容
    s7.insert(2,"****");
    cout << s7 << endl; //AS****AAAAAYYYWUWp

    //删除内容:erase() 参数1:删除的起止位置 参数2:删除的字符数
    s7.erase(4,3);
    cout << s7 << endl; //AS**AAAAYYYWUWp

    //替换:replace()  参数1:替换的起始位置 参数2:替换的字符数 参数3:替换的内容
    s7.replace(0,3,"++++");
    cout << s7 << endl;  //++++*AAAAYYYWUWp
    //遍历:使用for即可

    for(int i=0;i<s.size();i++)
    {
        cout<<s[i]<<" ";
    }
    
    cout<<endl;
    //清空:clear()
    s7.clear();
    cout << s7.size() << endl; //0
    return 0;
}

2.1.3 vector

vector内部使用数组实现,最常用的一种顺序容器,适合高效的进行随机存取,不适合插入和删除。可以理解为可变长度的数组,是一种顺序结构的线性表,故他的特性和线性表差不多,如随机访问;且插入删除的时间复杂度是O(n)。

关于vector指针的位置如图所示,我这里设置了一个最大长度为7里面包含5个元素的vector数组,其中first指针指向下标为0的元素,end指针指向最大长度的后一位。

 故last-first即为该表存储的数量,end-first=size即为该表的长度。

当插入的数值超范围后,vector会另外开辟出一块更大的空间用于存储,转移的顺序如下:

1. 转移表内的元素信息

2. 转移first、end、last等指针

3. 删除原有的表,完成转移

由上可知,为确保程序运行的效率,故vector无直接插在首位的函数如:frontpush,后面的list容器可以解决这种问题。

我们现在将我所整理的函数及其功能列出来:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    //创建一个长度为5向量对象
    vector<int> vec(5);
    cout << vec.size() << endl; //5
    //取出元素值
    cout << vec.at(0) << " " << vec[1] << endl; //0 0
    //向后添加元素
    vec.push_back(12);
    cout << vec.size() << endl; //6 此时长度为6,动态扩充
    //删除最后一个元素
    vec.pop_back();
    //在第二个位置插入元素222
    vec.insert(vec.begin()+1,222);

    //在倒数第二个位置插入元素4
    vec.insert(vec.end()-1,4);

    //删除倒数第一个元素
    vec.erase(vec.end()-1);


    cout << "-----for----" << endl;
    for(int i=0;i<vec.size();i++)
    {
        cout << vec.at(i) << " ";
    }
    cout << endl;

    //清空元素
    vec.clear();
    cout << vec.empty() << endl; //1
    return 0;
}

2.1.4 list

list内部由双向链表实现,元素的内存空间不连续,因此适合高效的进行插入和删除操作,但是不适合使用下标操作(只能通过迭代器指针操作元素),也不适合大量的随机存取。

#include <iostream>
#include <list>

using namespace std;

int main()
{
    //创建一个长度为4的列表对象,每个元素的初始值为“hello”
    list<string> lis(4,"hello");
    cout << lis.empty() << endl; //0
    //向后追加
    lis.push_back("hou");
    //向前追加
    lis.push_front("qian");
    cout << lis.size() << endl; //6

    //在第一个位置插入元素
    lis.insert(lis.begin(),"frist");
    //获取第一个元素
    cout << lis.front() << endl; //frist

    //在最后一个位置插入元素
    lis.insert(lis.end(),"finish");
    //获取最后一个元素
    cout << lis.back() << endl; //finish

    //    删除第一个元素
    lis.pop_front();
    cout << lis.front() << endl; //qian
    //删除最后一个元素
    lis.pop_back();
    cout << lis.back() << endl; //hou

    //第二个位置插入元素
    //注:list的迭代器指针不支持+,可以使用自增或自减
    lis.insert(++lis.begin(),"222");
    //在倒数第二个位置插入元素
    lis.insert(--lis.end(),"lala");

    //在第五个位置插入元素
    //     1、获取起始位置的迭代器指针 只读:const_iterator 可读写:iterator
    list<string>::iterator iter = lis.begin();
    //2、把迭代器指针向后移动4位(参数1:迭代器指针 参数2:向后移动的数量,负数为向前)
    advance(iter,4);
    //3、使用*取内容,即元素本身
    cout << "lis[4]:" << *iter << endl; //hello
    //4、插入元素"555"
    lis.insert(iter,"555");
    cout << "lis[4]:" << *iter << endl; //hello
    //修改第五个元素
    iter = lis.begin();
    advance(iter,4);
    *iter = "exo";
    //删除第四个元素
    iter = lis.begin();
    advance(iter,3);
    lis.erase(iter);

    //排序:按照编码方式
    //    lis.sort();

    //不支持for循环,但是支持foreach
    for(string i:lis)
    {
        cout << i << " ";
    }
    cout << endl;

    //清空
    //    lis.clear();
    //    cout << lis.empty() << endl; //1
    return 0;
}

2.1.5 deque

从API上基本同时兼容vector和list,随机存取和插入删除的性能都介于vector和list直接,算是一种比较均衡 的顺序容器类型。相对而言,deque比较擅长首尾两端的存取操作。因为兼容的缘故deque可以直接使用vector和list二者的函数用法,注意使用时要换函数介绍为deque

2.2 关联容器

各个元素直接没有严格的物理顺序,但是在内部由一个排序特点,因此就可以使用迭代器进行遍历。

常见的关联容器有:map(键值对映射)、multimap(多重键值对映射)等

以map为例,来说明关联容器的使用。

2.2.1 map

map以键值对的方式来存储元素数据,map与multimap的区别仅仅在于一个键对应一个值还是一个键对应多个值,map更为常用。

键作为数据的名称,具有唯一性,而值则不必。

键通过为字符串类型,而值则根据存储的数据类型而定。

#include <iostream>
#include <map>

using namespace std;

int main()
{
    //创建一个元素为空的map对象
    map<string,int> m;
    //插入元素
    m["身高"] = 188;
    m["体重"] = 50;
    m["存款"] = 12000;
    //如果这个键值对已经存在,则表示修改(键名改不了,只能修改值)
    m["存款"] = 15000;
    m.insert(pair<string,int>("年龄",27));
    m.insert(pair<string,int>("工龄",4));

    //在取出数据时应该先进行判断值是否存在,

    if(m.find("存款") != m.end())
    {
        //取出键对应的值 键--first 值--second
        cout << m.find("存款")->second << endl;
    }else
    {
        cout << "存款键不存在" << endl;
    }
    if(m.find("住址") != m.end())
    {
        //取出键对应的值 键--first 值--second
        cout << m.find("住址")->second << endl;
    }else
    {
        cout << "住址键不存在" << endl;
    }

    //删除键值对
    bool result = m.erase("体重");
    cout << m.size() << endl; //4
    if(result)
    {
        cout << "删除体重成功" << endl;
    }else
    {
        cout << "删除体重失败" << endl;
    }
    result = m.erase("收入");
    if(result)
    {
        cout << "删除收入成功" << endl;
    }else
    {
        cout << "删除收入失败" << endl;
    }

    //清空
    m.clear();
    cout << m.empty() << endl; //1
    return 0;
}

2.3 迭代器

C++中为每一个容器类都提供了对应的迭代器类型,用于遍历容器,迭代器是一个特殊的指针。

通常情况下,容器类型可以通过begin或end函数获得头部或尾部的跌大气,随后不断移动迭代器来取出所有的元素。

迭代器遍历的效率是各种方式中最高的。如果只读使用const_iterator,如果读写使用iterator。

#include <iostream>
#include <array>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <map>

using namespace std;

int main()
{
    string str = "hello";
    for(string::const_iterator iter = str.begin();iter!= str.end();iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    array<string,5> arr = {"aaa","bbb","ccc","ddd","eee"};
    for(array<string,5>::const_iterator iter = arr.begin();iter!= arr.end();iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    vector<double> vec;
    vec.push_back(11.2);
    vec.push_back(12.2);
    vec.push_back(13.2);
    vec.push_back(14.2);
    vec.push_back(15.2);
    for(vector<double>::const_iterator iter = vec.begin();iter!= vec.end();iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    list<string> lis;
    lis.push_back("AA");
    lis.push_back("BB");
    lis.push_back("CC");
    lis.push_back("DD");
    lis.push_back("EE");
    for(list<string>::const_iterator iter = lis.begin();iter!= lis.end();iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    deque<int> deq;
    deq.push_back(12);
    deq.push_back(13);
    deq.push_back(14);
    deq.push_back(15);
    deq.push_back(16);
    for(deque<int>::const_iterator iter = deq.begin();iter!= deq.end();iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    map<string,string> m;
    m["name"] = "Json";
    m["age"] = "18";
    m["sex"] = "man";
    m["money"] = "10000";
    m["car"] = "benchi";
    for(map<string,string>::const_iterator iter = m.begin();iter != m.end();iter++)
    {
        cout << iter->first << " " << iter->second;
    }
    cout << endl;


    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值