C++中STL介绍

转载自:https://blog.csdn.net/hhu1506010220/article/details/51971642

介绍

这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作。本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用。通过阅读这篇文章读者应该能够有效地使用vector容器,而且应该不会再去使用C类型的动态数组了。

Vector总览

vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。

Vector成员函数:

函数 表述
c.assign(begin,end)

c.assign(n,element)

截取c中[begin,end)区间的元素赋值给c

截取c中n个element的拷贝赋值给c

c.at(idx)传回索idx所指的数据,如果idx越界,抛出out_of_range
c.back()传回最后一个数据,不检查这个数据是否存在
c.begin()传回迭代器中的第一个数据
c.capacity()返回容器中的数据个数
c.clear()移除容器中的所有数据
c.empty()判断容器是否为空
c.end()传回迭代器中的最后一个数据地址
c.earse(pos)

c.earse(begin,end)

删除pos位置的数据,传回下一个数据的位置

删除[begin,end)区间的数据,传回下一个数据的位置

c.front()传回第一个数据
get_allocator使用构造函数返回一个拷贝
c.insert(pos,element)

c.insert(pos,n,element)

c.insert(pos,begin,end)

在pos位置插入一个element拷贝,传回新数据位置

在pos位置插入n个element数据,无返回值

在pos位置插入【begin,end)区间的数据,无返回值

c.max_size()返回容器中最大数据的数量
c.pop_back()删除最后一个数据
c.push_back(element)在尾部加入一个数据
c.rbegin()传回一个逆向队列的第一个数据
c.rend()传回一个逆向队列的最后一个数据的下一个位置
c.resize(num)重新制定队列的长度
c.reserve()

c.size()

c1.swap(c2)

swap(c1,c2)

vector c

vectorc1(c2)

vectorc(n)

vectorc(n,element)

vectorc(begin,end)

c.~vector()

保留适当的容量

返回容器中实际数据的个数

将c1和c2元素互换

同上

创建一个空的vector

复制一个vector

创建一个vector,含有n个元素,数据均已缺省构造产生

创建一个含有n个element拷贝的vector

创建一个以【begin,end)区间的vector

销毁所有数据,释放内存

创建一个Vector

1     vector<string> strv(500);//创建包含500个string类型数据的vector
2     vector<string> strv1(500,"0");//创建包含500个string类型数据的vector,并初始化为"0"
3     vector<string> strv2(strv);

向vector添加一个数据

vector添加数据的缺省方法是push_back()。push_back()函数表示将数据添加到vector的尾部,并按需要来分配内存。

1     vector<int> veri;
2     for(int i=0;i<10;i++){
3         veri.push_back(i);
4     }

获取vector中指定位置的数据

很多时候我们不必要知道vector里面有多少数据,vector里面的数据是动态分配的,使用push_back()的一系列分配空间常常决定于文件或一些数据源。如果你想知道vector存放了多少数据,你可以使用empty()。获取vector的大小,可以使用size()。例如,如果你想获取一个vector v的大小,但不知道它是否为空,或者已经包含了数据,如果为空想设置为-1,你可以使用下面的代码实现:

1 int nSize = v.empty() ? -1 : static_cast<int>(v.size());

访问vector中的数据

使用两种方法来访问vector。

1、vector::at()

2、vector::operator[]

operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。但at()是我们的首选,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。由于operator[]容易造成一些错误,所有我们很少用它,下面进行验证一下:

1     vector<int> v;
 2     v.reserve(10);
 3     for(int i=0; i<7; i++)
 4         v.push_back(i);
 5     try
 6     {
 7         int iVal1 = v[7];  // not bounds checked - will not throw
 8         int iVal2 = v.at(7); // bounds checked - will throw if out of range
 9     }
10     catch(const exception& e)
11     {
12         cout << e.what();
13     }

我们使用reserve()分配了10个int型的空间,但并不没有初始化。

你可以在这个代码中尝试不同条件,观察它的结果,但是无论何时使用at(),都是正确的。
删除vector中的数据vector能够非常容易地添加数据,也能很方便地取出数据,同样vector提供了erase(),pop_back(),clear()来删除数据,当你删除数据的时候,你应该知道要删除尾部的数据,或者是删除所有数据,还是个别的数据。在考虑删除等操作之前让我们静下来考虑一下在STL中的一些应用。压缩一个臃肿的vcetor
很多时候大量的删除数据,或者通过使用reserve(),结果vector的空间远远大于实际需要的。所有需要压缩vector到它实际的大小。resize()能够增加vector的大小。Clear()仅仅能够改变缓存的大小,所有的这些对于vector释放内存等九非常重要了。如何来解决这些问题呢,让我们来操作一下。

我们可以通过一个vector创建另一个vector。让我们看看这将发生什么。假定我们已经有一个vector veri,它的内存大小为1000,当我们调用size()的时候,它的大小仅为7。我们浪费了大量的内存。让我们在它的基础上创建一个vector。

1     vector<int> veri;
2     veri.reserve(1000);
3     for(int i=0;i<10;i++){
4         veri.push_back(i);
5     }
6     
7     cout << "veri capacity="<<veri.capacity()<<endl;
8     cout << "veri size="<<veri.size()<<endl;

C++中STL介绍

创建新的vector来与veri交换

1     vector<int> veri;
 2     veri.reserve(1000);
 3     for(int i=0;i<10;i++){
 4         veri.push_back(i);
 5     }
 6     
 7     cout << "veri capacity="<<veri.capacity()<<endl;
 8     cout << "veri size="<<veri.size()<<endl;
 9     
10     vector<int> veri1;
11     veri1.swap(veri);
12     
13     cout << "veri capacity="<<veri.capacity()<<endl;
14     cout << "veri size="<<veri.size()<<endl;
15     cout << "veri1 capacity="<<veri1.capacity()<<endl;
16     cout << "veri1 size="<<veri1.size()<<endl;

C++中STL介绍

新的vector的capacity变为1000,size为7。这样让没有达到目的

1     vector<int> veri;
 2     veri.reserve(1000);
 3     for(int i=0;i<10;i++){
 4         veri.push_back(i);
 5     }
 6     
 7     cout << "veri capacity="<<veri.capacity()<<endl;
 8     cout << "veri size="<<veri.size()<<endl;
 9     
10 //    vector<int> veri1;
11 //    veri1.swap(veri);
12     vector<int>(veri1).swap(veri1);
13     cout << "veri capacity="<<veri.capacity()<<endl;
14     cout << "veri size="<<veri.size()<<endl;
15 //    cout << "veri1 capacity="<<veri1.capacity()<<endl;
16 //    cout << "veri1 size="<<veri1.size()<<endl;

C++中STL介绍

达到目的!!!!

同时,测试一下clear,可以发现clear只是把内容清楚了,但vector的内存并没有释放掉,可以使用swap来彻底释放内存。

1     vector<int> veri;
 2     veri.reserve(1000);
 3     for(int i=0;i<10;i++){
 4         veri.push_back(i);
 5     }
 6     cout << "veri capacity="<<veri.capacity()<<endl;
 7     cout << "veri size="<<veri.size()<<endl;
 8 
 9     veri.clear();
10     cout << "veri capacity="<<veri.capacity()<<endl;
11     cout << "veri size="<<veri.size()<<endl;
12     vector<int>(veri).swap(veri);
13     cout << "veri capacity="<<veri.capacity()<<endl;
14     cout << "veri size="<<veri.size()<<endl;

C++中STL介绍

迭代器

1 // vector.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <vector>
 6 #include <iostream>
 7 #include <numeric>
 8 #include <algorithm>
 9 using namespace std;
10 
11 bool Comp(const int &a,const int &b){
12 
13     return a > b;
14 }
15 int _tmain(int argc, _TCHAR* argv[])
16 {
17     vector<int> vec;
18     //添加元素
19     vec.push_back(10);
20     vec.push_back(20);
21     vec.push_back(30);
22 
23     vector<int>::iterator vecit ;
24     cout << "初始:";
25     for(vecit=vec.begin();vecit!=vec.end();vecit++){
26         cout << *vecit << " ";
27     }
28     cout <<endl;
29 
30     cout << "求和="<<accumulate(vec.begin(),vec.end(),0)<<endl;
31 
32     //插入
33     vec.insert(vec.begin(),1);
34     vec.insert(vec.end(),40);
35     cout << "插入:";
36     for(vecit=vec.begin();vecit!=vec.end();vecit++){
37         cout << *vecit << " ";
38     }
39     cout <<endl;
40     //删除
41     vec.erase(vec.begin());
42     cout << "删除:";
43     vec.erase(vec.begin(),vec.begin()+2);
44     for(vecit=vec.begin();vecit!=vec.end();vecit++){
45         cout << *vecit << " ";
46     }
47     cout <<endl;
48     //转置
49     reverse(vec.begin(),vec.end());
50     cout << "转置:";
51     for(vecit=vec.begin();vecit!=vec.end();vecit++){
52         cout << *vecit << " ";
53     }
54     cout <<endl;
55 
56     vec.push_back(1);
57     vec.push_back(3);
58     vec.push_back(2);
59     vec.push_back(55);
60     vec.push_back(-1);
61     vec.push_back(0);
62     vec.push_back(2);
63     vec.push_back(3);
64     vec.push_back(4);
65     cout << "初始:";
66     for(vecit=vec.begin();vecit!=vec.end();vecit++){
67         cout << *vecit << " ";
68     }
69     cout <<endl;
70     sort(vec.begin(),vec.end());
71     cout << "升序:";
72     for(vecit=vec.begin();vecit!=vec.end();vecit++){
73         cout << *vecit << " ";
74     }
75     cout <<endl;
76     sort(vec.begin(),vec.end(),Comp);
77     cout << "降序:";
78     for(vecit=vec.begin();vecit!=vec.end();vecit++){
79         cout << *vecit << " ";
80     }
81     cout <<endl;
82     return 0;
83 }

C++中STL介绍

字符串

输入:

1 #include "stdafx.h"
 2 #include <string>
 3 #include <iostream>
 4 
 5 using namespace  std;
 6 int _tmain(int argc, _TCHAR* argv[])
 7 {
 8     string s1;
 9     s1 = "hello";
10     string s2;
11     char s[1024];
12     //scanf输入速度比cin快的多,但是scanf是c函数,不能输入字符串
13     scanf("%s",s);
14     s2 = s;
15     cout << s1 << endl;
16     cout << s2 << endl;
17     return 0;
18 }

尾部添加字符字符串直接用+号 例如: s += 'a'; s += "abc",或者使用append方法,s.append(“123”)

删除:

1 // string1.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <string>
 6 #include <iostream>
 7 
 8 using namespace  std;
 9 int _tmain(int argc, _TCHAR* argv[])
10 {
11     string s;
12     s = "0123456789";
13 
14     string::iterator it = s.begin();
15     s.erase(it+3);//删除s[3]
16     cout << s << endl;
17 
18     s = "0123456789";
19     s.erase(it+1,it+4);//删除s[1]-s[3]
20     cout << s << endl;
21 
22     s.clear();
23     cout << s << endl;
24 }

C++中STL介绍

查找(find)

用find找到string里面第一个要找到元素(char或者串),找到返回数组下标,找不到返回end()迭代器

string和vector有很多相同的东西,比如length(),size(),empty(),reverse(),相对也容易,就不一一说了。

数字化处理(string)

经常会遇到这样一种情况,有一个数字,需要把每一位给提取出来,如果用取余数的方法,花费的时间就会很长,所以可以当成字符串来处理,方便、省时。

例子:求一个整数各位数的和

1 // string1.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <string>
 6 #include <iostream>
 7 
 8 using namespace  std;
 9 int _tmain(int argc, _TCHAR* argv[])
10 {
11     string s;
12     s = "0123456789";
13     int sum = 0;
14     for(int i=0;i<s.size();i++){
15         switch(s.at(i)){
16         case '1':sum+=1;break;
17         case '2':sum+=2;break;
18         case '3':sum+=3;break;
19         case '4':sum+=4;break;
20         case '5':sum+=5;break;
21         case '6':sum+=6;break;
22         case '7':sum+=7;break;
23         case '8':sum+=8;break;
24         case '9':sum+=9;break;
25         }
26     }
27     cout << "sum =" << sum << endl;
28     
29 }

string与数值相互转换( sprintf )

1 // string1.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <string>
 6 #include <iostream>
 7 #include <sstream>
 8 using namespace  std;
 9 
10 string converToString(double x){
11     ostringstream o;
12     if(o << x){
13         return o.str();
14     }
15     return "error";
16 }
17 
18 double converFromString(string s){
19     istringstream i(s);
20     double x;
21     if(i >> x){
22         return x;
23     }
24     return 0.0;
25 }
26 int _tmain(int argc, _TCHAR* argv[])
27 {
28     char b[100];
29     sprintf(b,"%d",1987);
30     string s1 ;
31     s1 = b;
32     cout << s1 << endl;
33 
34     string s2 = converToString(1954);
35     cout << s2 << endl;
36 
37     string s3 = "202";
38     int c = converFromString(s3);
39     cout << c << endl;
40 
41     string s4 = "casacsa6";
42     int d = converFromString(s4);
43     cout << d << endl;
44 
45     string s5 = "31af12";
46     int f = converFromString(s5);
47     cout << f << endl;
48     return 0;
49 }

C++中STL介绍

set容器

set是用红黑树的平衡二叉索引树的数据结构来实现的,插入时,它会自动调节二叉树排列,把元素放到适合的位置,确保每个子树根节点的键值大于左子树所有的值、小于右子树所有的值,插入重复数据时会忽略。set迭代器采用中序遍历,检索效率高于vector、deque、list,并且会将元素按照升序的序列遍历。set容器中的数值,一经更改,set会根据新值旋转二叉树,以保证平衡,构建set就是为了快速检索(python中的set一旦建立就是一个常量,不能改的)。C++中STL介绍

multiset,与set不同之处就是它允许有重复的键值。

set的正反遍历:迭代器iterator,reverse_iterator

1 // string1.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <set>
 6 #include <iostream>
 7 
 8 using namespace  std;
 9 
10 int _tmain(int argc, _TCHAR* argv[])
11 {
12     set<int> v;
13     v.insert(1);
14     v.insert(5);
15     v.insert(7);
16     v.insert(2);
17     v.insert(4);
18     v.insert(10);
19 
20     //中序遍历=升序遍历
21     set<int>::iterator it;
22     for(it=v.begin();it!=v.end();it++){
23         cout << *it << " ";
24     }
25     cout << endl;
26 
27     set<int>::reverse_iterator it1;
28     for(it1=v.rbegin();it1!=v.rend();it1++){
29         cout << *it1 << " " ;
30     }
31     cout << endl;
32     
33     return 0;
34 }

自定义比较函数,insert的时候,set会使用默认的比较函数(升序),很多情况下需要自己编写比较函数。

1、如果元素不是结构体,可以编写比较函数,下面这个例子是用降序排列的(和上例插入数据相同):

1 // string1.cpp : 定义控制台应用程序的入口点。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <set>
 6 #include <iostream>
 7 
 8 using namespace  std;
 9 
10 
11 struct Comp
12  {
13     //重载()
14      bool operator()(const int &a, const int &b)
15      {
16          return a > b;
17      }
18  };
19 int _tmain(int argc, _TCHAR* argv[])
20 {
21     set<int> v;
22     v.insert(1);
23     v.insert(5);
24     v.insert(7);
25     v.insert(2);
26     v.insert(4);
27     v.insert(10);
28 
29     //中序遍历=升序遍历
30     set<int>::iterator it;
31     for(it=v.begin();it!=v.end();it++){
32         cout << *it << " ";
33     }
34     cout << endl;
35 
36     set<int,Comp>::reverse_iterator it1;
37     for(it1=v.rbegin();it1!=v.rend();it1++){
38         cout << *it1 << " " ;
39     }
40     cout << endl;
41     
42     return 0;
43 }

map

map也是使用红黑树,他是一个键值对(key:value映射),便利时依然默认按照key程序的方式遍历,同set。

multimap

multimap由于允许有重复的元素,所以元素插入、删除、查找都与map不同。

插入insert(pair(value1,value2))

至于删除和查找,erase(key)会删除掉所有key的map,查找find(key)返回第一个key的迭代器

deque

deque和vector一样,采用线性表,与vector唯一不同的是,deque采用的分块的线性存储结构,每块大小一般为512字节,称为一个deque块,所有的deque块使用一个Map块进行管理,每个map数据项记录各个deque块的首地址,这样以来,deque块在头部和尾部都可已插入和删除元素,而不需要移动其它元素。使用push_back()方法在尾部插入元素,使用push_front()方法在首部插入元素,使用insert()方法在中间插入元素。一般来说,当考虑容器元素的内存分配策略和操作的性能时,deque相对vectore更有优势。

(下面这个图,我感觉Map块就是一个list< map >)

C++中STL介绍

插入删除

遍历当然可以使用下标遍历,在这里使用迭代器。

list

list l

插入:push_back尾部,push_front头部,insert方法前往迭代器位置处插入元素,链表自动扩张,迭代器只能使用++--操作,不能用+n -n,因为元素不是物理相连的。

遍历:iterator和reverse_iterator正反遍历

删除:pop_front删除链表首元素;pop_back()删除链表尾部元素;erase(迭代器)删除迭代器位置的元素,注意只能使用++--到达想删除的位置;remove(key) 删除链表中所有key的元素,clear()清空链表。

查找:it = find(l.begin(),l.end(),key)

排序:l.sort()

删除连续重复元素:l.unique() 【2 8 1 1 1 5 1】 --> 【 2 8 1 5 1】

bitset

从来没用过,上两幅图吧就:

C++中STL介绍

C++中STL介绍

stack(后进先出)

这个印象深刻,学数据结构的时候做表达式求值的就是用的栈。
原文链接: https://www.cnblogs.com/zhangjxblog/p/8902010.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/272709

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 下午10:57
下一篇 2023年2月14日 下午10:58

相关推荐