C++ STL容器使用

list 用法整理

list 实现
list 容器是由双向链表实现的,因此不能使用下标运算符 [] 访问其中的元素。

使用 list 的时候得加上 #include 头文件以及得在 std 名字空间中使用。

list 定义和初始化
只需要简单的 list my_list; 就可以完成对一个 list 的定义了。不需要 new。

初始化的话就要用到 list 的构造函数。

  int a[] = {1,2,3,4};
  list<int> mylist (a, a+4);

list访问

    for ( list<int>::iterator it=m_list.begin(); it != m_list.end(); ++it) {
        cout<<*it<<endl;
    }

list 函数介绍
迭代器
在这里插入图片描述
C++ 11 标准又新增 cbegin, cend, crbegin 和 crend 这四个函数,返回的都是 const_iterator。
容量
在这里插入图片描述
元素访问
在这里插入图片描述
修改
在这里插入图片描述
C++ 11 标准又增加了 emplace_front, emplace_back, emplace 这三个函数
操作
在这里插入图片描述
了解详情或例子:点击C ++ list 用法整理(官网例子)

vector使用总结

vector实现

vector的底层实现原理是数组,占用连续的内存空间,与普通数组不同,vector是一个动态数组,意思是vector不是大小固定的数组,vector的大小会随着元素的不断变多而变大,vector有两个关键属性,size和capacity。size表示的是vector当前存放了多少个元素,capacity表示的是当前vector总共能存多少个元素。capacity总是大于等于size,如果size已经等于capacity,再往vector中添加元素,此时会重新分配一段更大的内存(原来内存大小的2倍或1.5倍),然后将旧内存中的数据拷贝到新内存,最后释放旧内存。

vector特点:

(1) 一个动态分配的数组(当数组空间内存不足时,都会执行: 分配新空间-复制元素-释放原空间);

(2) 当删除元素时,不会释放限制的空间,所以向量容器的容量(capacity)大于向量容器的大小(size);

(3) 对于删除或插入操作,执行效率不高,越靠后插入或删除执行效率越高;

(4) 高效的随机访问的容器。

了解vector原理详情C++ vector实现原理

vector定义和初始化

vector 可以有五种方式

//定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的,一般为0。
   1)vector<int> a(10); 
   2)vector<int> a(10,1); //定义了10个整型元素的向量,且给出每个元素的初值为1
   3)vector<int> a(b); //用b向量来创建a向量,整体复制性赋值
   4)vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
   5int b[7]={1,2,3,4,5,9,8};
      vector<int> a(b,b+7); //从数组中获得初值

vector方法介绍

(1)a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
(2)a.assign(4,2); //是a只含4个元素,且每个元素为2
(3)a.back(); //返回a的最后一个元素
(4)a.front(); //返回a的第一个元素
(5)a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07
(6)a.clear(); //清空a中的元素
(7)a.empty(); //判断a是否为空,空则返回ture,不空则返回false
(8)a.pop_back(); //删除a向量的最后一个元素
(9)a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,
也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+ 3(不包括它)
(10)a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
(11)a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
(12)a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
(13)a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),
如b为1,2,3,4,5,9,8 , 插入元素后为1,4,5,9,2,3,4,5,9,8
(14)a.size(); //返回a中元素的个数;
(15)a.capacity(); //返回a在内存中总共可以容纳的元素个数
(16)a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
(17)a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
(18)a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.
这种操作只有在需要给a添加大量数据的时候才         
显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能) 
(19)a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
(20)a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<

vector访问

    for ( vector<int>::iterator it=m_vector.begin(); it != m_vector.end(); ++it) {
        cout<<*it<<endl;
    }

size和capacity的区别

size()函数返回的是已用空间大小,capacity()返回的是总空间大小,capacity()-size()则是剩余的可用空间大小。当 size()==capacity(),说明 vector 目前的空间已被用完,如果再添加新元素,则会引起 vector 空间的动态增长。

resize和reserve的区别

reserve()只修改capacity大小,不修改size大小;resize()既修改capacity大小,也修改size大小。reserve(n)预先分配一块较大的指定大小的内存空间,这样当指定大小的内存空间未使用完时,是不会重新分配内存空间的,这样便提升了效率。只有当 n>capacity()时,调用 reserve(n)才会改变 vector 容量。resize()成员函数只改变元素的数目,不改变 vector 的容量。

size和max_size的区别

size()是向量的大小,当前存入的元素个数;max_size是此类向量在当前平台上能处理的最大元素个数,存放数据类型不同值就不同,所在平台是32还是64位值也不同。

vector几种重要的算法

使用时需要包含头文件:

#include<algorithm>
  • 1、对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
  sort(a.begin(),a.end()); 
  • 2、对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
  reverse(a.begin(),a.end()); 
  • 3、 把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素,如果b长度小于a,则只能复制部分
  copy(a.begin(),a.end(),b.begin()+1);
  • 4、在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置,
    未找到,则指向最后一个即返回 a.end();
  find(a.begin(),a.end(),10); 

vector使用注意

vector<int> a;
for(int i=0;i<10;i++)
a[i]=i;
//这种做法以及类似的做法都是错误的。下标只能用于获取已存在的元素,而现在的a[i]还是空的对象
  1. 空的 vector即empty()==true时,size()和 capacity()都为 0。
  2. 当空间大小不足时,新分配的空间大小为原空间大小的 2 倍。
  3. 使用 reserve()预先分配一块内存后,在空间未满的情况下,不会引起重新分配,从而提升了效率。
  4. 当 reserve()分配的空间比原空间小时,是不会引起重新分配的。
  5. resize()函数只改变容器的元素数目,未改变容器大小。
  6. 用 reserve(size_type)只是扩大 capacity 值,这些内存空间可能还是“野”的,如果此时使用“[ ]”来访问,则可能会越界。而 resize(size_type new_size)会真正使容器具有 new_size 个对象。

二分法

#include<iostream>
#include<vector>
using namespace std;
void output(vector<int> m_list)
{
    for ( vector<int>::iterator it=m_list.begin(); it != m_list.end(); ++it) {
        cout<<*it<<endl;
    }
}
int  main()
{
    vector<int> v(10);
    for (int var = 0; var < 10; ++var) {
       v[var] = var;
    }
    output(v);
    vector<int>::iterator it_begin=v.begin();
    vector<int>::iterator it_end=v.end();
    vector<int>::iterator it_mid=v.begin()+(it_end-it_begin)/2;

    int number;
    cin>>number;

    while(  it_begin < it_end){

        if(number < *it_mid){
            it_end = it_mid;
        }else if(number > *it_mid){
            it_begin = it_mid+1;
        }else{
            break;
        }

        it_mid = it_begin + (it_end - it_begin)/2;
    }

    if(number == *it_mid)
        cout<<"find"<<endl;
    else
        cout<<"oh no!"<<endl;
    return 0;
}

deque容器使用总结

deque容器是C++标准模版库(STL,Standard Template Library)中的部分内容。deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque还支持从开始端插入数据:push_front()。双端数组,可以对头端进行插入删除操作。

deque内部工作原理

deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据

中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

在这里插入图片描述

deque定义和初始化

deque c 创建一个空的deque

deque<Elem> c1(c2) 复制一个deque。

deque<Elem> c(n) 创建一个deque,含有n个数据,数据均已缺省构造产生。

deque<Elem> c(n, elem) 创建一个含有n个elem拷贝的deque。

deque<Elem> c(beg,end) 创建一个以[beg;end)区间的deque。

~deque<Elem>() 销毁所有数据,释放内存。

deque常用方法

deque大小操作

deque.empty(); //判断容器是否为空
deque.size(); //返回容器中元素的个数
deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
​ //如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
​ //如果容器变短,则末尾超出容器长度的元素被删除。

deque 插入和删除

push_back(elem); //在容器尾部添加一个数据
push_front(elem); //在容器头部插入一个数据
pop_back(); //删除容器最后一个数据
pop_front(); //删除容器第一个数据

insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。
clear(); //清空容器的所有数据
erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos); //删除pos位置的数据,返回下一个数据的位置。

deque 数据存取

at(int idx); //返回索引idx所指的数据
operator[]; //返回索引idx所指的数据
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素

deque排序

	sort(iterator beg, iterator end) //对beg和end区间内元素进行排序

deque与vector区别

  • 1、vector对于头部的插入删除效率低,数据量越大,效率越低
  • 2、deque相对而言,对头部的插入删除速度回比vector快
  • 3、vector访问元素时的速度会比deque快,这和两者内部实现有关

set/multiset容器

set和multiset属于关联式容器,会根据特定的排序原则,将内部元素自动排序,通常以红黑树完成,(保证了到达某一元素的最长路径的深度至多是最短路径的深度的两倍)。

自动排序的优点在于其查找函数具有对数复杂度,在小数据量(元素数量<=1000)的情况下二叉树查找动作(由stl成员函数执行)平均时间仅为线性查找的1/50。

有利必有弊,因自动排序的存在,你不能直接改变容器中的元素值,提供的改变的方法是删除旧元素,插入新元素。

1.set和multiset不提供任何操作函数可以直接访问元素。

2.通过迭代器对元素进行间接访问,有一个限制:从迭代器角度看,元素是常量。

set和multiset使用须知

1.set和multiset的区别在于multiset允许元素重复而set不允许。

2.包含头文件

#include<set>

3.只要是可依据某排序准则被比较的任意类型T都可以成为set或multiset的元素类型。

set和multiset的操作函数

创建

     set<elem> c;           //defalut构造函数,创建一个元素类型为elem的空的set/multiset,不含任何元素
     set<elem> c(c2);
     set<elem> c=c2;        //copy构造函数,建立一份c2的拷贝,所有元素均被复制
     set<elem> c(beg,end);  //以区间[beg,end)内的元素为初值,建立一个set/multiset

在这里要注意,建立的所有set的排序方式都是默认为仿函数 less<>,在此我们不对构造排序函数作过多介绍,仅提供一个反序的仿函数

set<elem,greater<elem>> c; //以与less<>反序的排序准则创建的一个元素类型为elem的空set/multiset

非更易型操作

set和multiset提供的非更易型操作用来查询大小,相互比较(比较采用的是字典序),同样的,set重载了">,<,==,!=,>=,<="一系列比较运算符

     c.empty();      //返回是否容器为空
     c.size();       //返回容器目前元素个数
     c.max_size();   //返回容器元素个数之最大可能量
     c.key_comp();   //返回比较准则
     c.value_comp(); //返回针对value的比较准则

特殊的查找函数

以下函数是同名的stl算法的基于set与multiset的特殊版本,对这两个容器使用以下查找可获得对数复杂度。

     c.count(val);       //返回“元素值为val”的元素个数
     c.find(val);        //返回“元素值为val”的第一个元素(迭代器),找不到就返回容器的end()
     c.lower_bound(val); //返回val的第一个可安插位置,也就是“元素值>=val”的第一个元素位置(迭代器)
     c.upper_bound(val); //返回val的最后一个可安插位置,也就是“元素值>val”的第一个元素位置(迭代器)
     c.equal_range(val); //返回一个pair,将lower_bound和upper_bound分别作为first和second,也就是返回一个区间

迭代器相关函数

     c.begin();  //返回一个bidirectional iterator指向第一元素
     c.end();    //返回一个bidirectional iterator指向最末元素的下一位置
     c.rbegin(); //返回一个reverse iterator指向反向迭代的第一元素
     c.rend();   //返回一个reverse iterator指向反向迭代的最末元素的下一位置

元素的安插和移除

     c.insert(val);     //安插一个val拷贝,返回新元素位置,无论是否成功(对set而言)
     c.insert(pos,val); //安插一个val拷贝,返回新元素位置(pos是一个提示,提示安插动作的查找起点,若提示恰当可以加快速度)
     c.insert(beg,end); //将区间[beg,end)内所有元素的拷贝安插到c(无返回值)
     c.erase(val);      //移除与val相等的所有元素,返回被移除的元素个数
     c.erase(pos);      //移除iterator位置pos上的元素,无返回值
     c.erase(beg,end);  //移除区间[beg,end)内的所有元素,无返回值
     c.clear();         //移除所有元素,清空容器

统计和查找

  • 1、find( elem ):查找函数接口,当查找到elem元素时,会返回相应的迭代器,反之返回end()迭代器;

  • 2、count( elem ):统计元素的个数,该接口在set容器中,返回的要么0(没有该元素),要么返回1(set不允许有重复的元素存在);在multiset容器中,则不一样,它允许有重复的元素出现,故返回值可能大于1。

set集合元素排序, 对类进行排序

#include<iostream>
#include <set>
using namespace std;
struct People
{
    People(string name,int age,bool sex):m_name(name),m_age(age),m_sex(sex) {}
public:
    string m_name;
    int m_age;
    bool m_sex;

};

struct Func
{
    bool operator()(const People &left, const People &right)
    {
        if (left.m_age < right.m_age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};
void output(set<People,Func> m_list)
{
    for ( set<People,Func>::iterator it=m_list.begin(); it != m_list.end(); ++it) {
        cout<<it->m_name<<" "<<it->m_age<<" "<<it->m_sex<<endl;
    }
}

int  main()
{
    set<People,Func> set1;
    string name1="name1";
    string name2="name2";
    string name3="name3";

    People p1(name1,12,true);
    People p2(name2,14,false);
    People p3(name2,13,true);

    set1.insert(p1);
    set1.insert(p2);
    set1.insert(p3);



   output(set1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值