标签:replace tostring class tps table 空间 没有初始化 image asa
转载自: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<element> c vector<element>c1(c2) vector<element>c(n) vector<element>c(n,element) vector<element>c(begin,end) c.~vector<element>() |
保留适当的容量 返回容器中实际数据的个数 将c1和c2元素互换 同上 创建一个空的vector 复制一个vector 创建一个vector,含有n个元素,数据均已缺省构造产生 创建一个含有n个element拷贝的vector 创建一个以【begin,end)区间的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中的数据很多时候大量的删除数据,或者通过使用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;
创建新的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;
新的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;
达到目的!!!!
同时,测试一下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;
迭代器
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 }
字符串
输入:
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 }
查找(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 <sstream> )
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 }
set容器
set是用红黑树的平衡二叉索引树的数据结构来实现的,插入时,它会自动调节二叉树排列,把元素放到适合的位置,确保每个子树根节点的键值大于左子树所有的值、小于右子树所有的值,插入重复数据时会忽略。set迭代器采用中序遍历,检索效率高于vector、deque、list,并且会将元素按照升序的序列遍历。set容器中的数值,一经更改,set会根据新值旋转二叉树,以保证平衡,构建set就是为了快速检索(python中的set一旦建立就是一个常量,不能改的)。
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<a,b>(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<deque名字,deque地址> >)
插入删除
遍历当然可以使用下标遍历,在这里使用迭代器。
list
list<int> 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
从来没用过,上两幅图吧就:
stack(后进先出)
这个印象深刻,学数据结构的时候做表达式求值的就是用的栈。
标签:replace tostring class tps table 空间 没有初始化 image asa
原文地址:https://www.cnblogs.com/zhangjxblog/p/8902010.html