1. 顺序容器的初始化操作
1.1 顺序容器(vector,list,deque)的五种初始化方法,以 vector 为例。
#include <iostream> #include <string> #include <vector> using namespace std; int main(int argc, const char *argv[]) { //1.定义空数组 然后后面追加 vector<string> vec1; vec1.push_back("beijing"); vec1.push_back("shanghai"); vec1.push_back("guangzhou"); vec1.push_back("shenzhen"); cout << "1----------------------------" << endl; for(vector<string>::iterator it = vec1.begin(); it != vec1.end(); ++it){ cout << *it << endl; } //2.定义时指定大小 然后依次赋值 vector<string> vec2(5); for(vector<string>::size_type ix = 0; ix != 5; ix++){ vec2[ix] = "tencent"; } cout << "2----------------------------" << endl; for(vector<string>::iterator it = vec2.begin(); it != vec2.end(); ++it){ cout << *it << endl; } //3.定义时指定大小并赋初值 vector<string> vec3(4, "facebook"); cout << "3----------------------------" << endl; for(vector<string>::iterator it = vec3.begin(); it != vec3.end(); ++it){ cout << *it << endl; } //4.用一个容器去初始化另一个容器 vector<string> vec4(vec1); cout << "4----------------------------" << endl; for(vector<string>::iterator it = vec4.begin(); it != vec4.end(); ++it){ cout << *it << endl; } //5.用一个迭代器的范围去初始化一个容器 vector<string> vec5(vec1.begin(), vec1.end()); cout << "5----------------------------" << endl; for(vector<string>::iterator it = vec5.begin(); it != vec5.end(); ++it){ cout << *it << endl; } return 0; }
1.2 用迭代器的一段范围去初始化一个容器时,两种容器可以是不同的容器,只要容器元素类型兼容即可(这个兼容的意思有两层,一是容器vec和容器list可以相互转化,二是容器中的类型比如vec<int> 和 vec<double>可以相互转化,总结来说就是, vec<int> 和 list<double> 可以相互转化)。当用一个容器去初始化另一个容器的时候,容器类型和容器内的元素类型 都必须相同。
#include <iostream> #include <string> #include <vector> #include <list> #include <algorithm> using namespace std; /* *用迭代器的一段范围初始化容器 *被初始化的容器可以使另一种容器 */ int main(int argc, const char *argv[]) { list<string> lst; lst.push_back("apple"); lst.push_back("google"); lst.push_back("microsoft"); lst.push_back("oracle"); list<string>::iterator res = find(lst.begin(), lst.end(), "google"); if(res == lst.end()){ cout << "not found" << endl; return -1; } vector<string> vec(res, lst.end()); for(vector<string>::iterator it = vec.begin(); it != vec.end(); ++it){ cout << *it << endl; } return 0; }
1.3 vector 和 list 的区别
a) vector 内部采用原生数组实现, list 则是基于链表;
b) vector 支持随机访问,list 只能顺序访问, 不支持下标操作(如下例所示,会出错,提示没有[]操作符)。
#include <iostream> #include <string> #include <list> using namespace std; int main(int argc, const char *argv[]) { list<string> lst; lst.push_back("apple"); lst.push_back("google"); lst.push_back("microsoft"); cout << lst[1] << endl; return 0; }
1.4 STL中容器内的元素必须支持复制和赋值操作。如下例所示,会出错。这里要注意,push_back实际放入的是元素的副本,所以要求元素必须具有复制的能力。
#include <iostream> #include <string> #include <vector> using namespace std; /* *容器中的元素类型必须支持复制和 赋值操作 * */ class Test{ Test(){} private: /* *下面第一行用于复制 *第二行用于赋值 *这里均设为私有,使得Test失去复制和赋值的能力 */ Test(const Test &); Test &operator=(const Test &); }; int main(int argc, const char *argv[]) { vector<Test> vec; Test t; vec.push_back(t); //push_back操作是把对象的副本放进去 而非对象本身 return 0; }
2. 迭代器
2.1 顺序容器中 begin 指向第一个元素 ,end 指向最后一个元素的下一个位置, rbegin 指向最后一个元素, rend指向第一个元素的前一个位置。即迭代器有顺序迭代器和逆序迭代器之分,如下例所示。
#include <iostream> #include <string> #include <vector> #include <list> using namespace std; int main(int argc, const char *argv[]) { list<string> lst; lst.push_back("google"); lst.push_back("oracle"); lst.push_back("apple"); for(list<string>::iterator it = lst.begin(); it != lst.end(); ++it){ cout << *it << endl; } cout << "-----------" << endl; /* *逆序迭代器 */ for(list<string>::reverse_iterator it = lst.rbegin(); it != lst.rend(); ++it){ cout << *it << endl; } return 0; }
3. 顺序容器的插入和删除操作
3.1 插入操作
3.1.1 insert 是插入到当前迭代器所指向的位置,其他元素依次后移,如下例所示。
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { vector<string> vec; vec.push_back("apple"); vec.push_back("google"); vec.push_back("oracle"); vec.push_back("ebay"); vector<string>::iterator res = find(vec.begin(), vec.end(), "oracle"); if(res == vec.end()){ cout << "not found" << endl; return -1; } vec.insert(res, "facebook"); for(vector<string>::iterator it = vec.begin(); it != vec.end(); ++it){ cout << *it << endl; } return 0; }
3.1.2 insert (p, n, t); 即insert重载了可以一次插入多个相同对象的的函数。如下例所示。
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { vector<string> vec; vec.push_back("apple"); vec.push_back("google"); vec.push_back("microsoft"); vector<string>::iterator res = find(vec.begin(), vec.end(), "google"); if(res == vec.end()){ cout << "not found" << endl; return -1; } vec.insert(res, 3, "jingdong"); for(vector<string>::iterator it = vec.begin(); it != vec.end(); ++it){ cout << *it << endl; } return 0; }
3.1.3 inset(p, begin, end) ;即insert 可以把一个容器的迭代器指向的一段范围插入到当前容器中,如下。
#include <iostream> #include <string> #include <vector> #include <list> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { vector<string> vec; vec.push_back("apple"); vec.push_back("google"); vec.push_back("microsoft"); vector<string>::iterator res = find(vec.begin(), vec.end(), "google"); if(res == vec.end()){ cout << "not found" << endl; return -1; } list<string> lst; lst.push_back("baidu"); lst.push_back("tencent"); lst.push_back("alibaba"); vec.insert(res, lst.begin(), lst.end()); for(vector<string>::iterator it = vec.begin(); it != vec.end(); ++it){ cout << *it << endl; } return 0; }
3.1.4 vector 不支持 push_front 操作,list 支持。如下例所示将报错。
#include <iostream> #include <string> #include <vector> using namespace std; int main(int argc, const char *argv[]) { vector<string> vec; vec.push_back("baidu"); vec.push_back("alibaba"); vec.push_back("tencent"); vec.push_front("huawei"); return 0; }
#include <iostream> #include <string> #include <vector> #include <list> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { vector<string> vec; vec.push_back("apple"); vec.push_back("google"); vec.push_back("microsoft"); list<string> lst(vec.begin(), vec.end()); lst.push_front("facebook"); for(list<string>::iterator it = lst.begin(); it != lst.end(); ++it){ cout << *it << endl; } return 0; }
4. 删除操作
4.1 pop_front 和 pop_back删除第一个 和最后一个。
#include <iostream> #include <string> #include <vector> #include <list> using namespace std; int main(int argc, const char *argv[]) { list<string> lst; lst.push_back("apple"); lst.push_back("google"); lst.push_back("microsoft"); lst.push_back("oracle"); lst.push_back("IBM"); lst.pop_front(); for(list<string>::iterator it = lst.begin(); it != lst.end(); ++it){ cout << *it << endl; } cout << "-------------" << endl; lst.pop_back(); for(list<string>::iterator it = lst.begin(); it != lst.end(); ++it){ cout << *it << endl; } return 0; }
4.2 erase 删除某一迭代器所指向的元素 或者 迭代器 所指向的一段区间。
#include <iostream> #include <string> #include <vector> #include <list> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { list<string> lst; lst.push_back("apple"); lst.push_back("google"); lst.push_back("microsoft"); lst.push_back("oracle"); lst.push_back("IBM"); list<string>::iterator res = find(lst.begin(), lst.end(), "microsoft"); if(res == lst.end()){ cout << " not found" << endl; return -1; } lst.erase(res);
// lst.erase(res, lst.end());
// for(list<string>::iterator it = lst.begin(); it != lst.end(); ++it){ cout << *it << endl; }
5.3 在容器中删除元素时,会导致该元素的迭代器失效,所以当使用erase时,应该用迭代器接收返回值。如下就是迭代器失效的例子,程序出错。
#include <iostream> #include <string> #include <vector> using namespace std; /* *erase 删除元素是 该迭代器会失效 *erase 操作返回下一个元素的迭代器 */ int main(int argc, const char *argv[]) { vector<int> vec; vec.push_back(2); vec.push_back(4); vec.push_back(5); vec.push_back(4); for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it){ if(*it % 2 == 0){ vec.erase(it);//此时it 指针失效 程序 core dump // 应改为 it = vec.erase(it); } } for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it){ cout << *it << endl; } return 0; }
5. vector 内存分配策略
5.1 顺序表的两个容量
a) size: 表示当前存储的元素数量;
b) capacity:表示预先分配的可容纳元素的最大数量。
c)我们通常所说的大小是指size,而不是capacity。vector下标的合法范围是0~size()-1。
5.2 在vector中,size 是存储的元素数量,resize 是改变当前存储的元素数量,这两个函数都属于第一种容量。而 capacity表 示 vector 的最大容量,reserve可以改变最大容量。
a) size:教室的当前人数
b) resize:改变当前的人数
c) capacity:教室可容纳的最大人数
d) reserve:改变教室的容纳量
5.3 vector的内存分配策略:
a) 定义空数组时,capacity为0,当制定vec大小为n的时候,capacity也为n。
b) 当capacity占满的时候,此时再次放入元素,capacity变为原来的两倍。
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { vector<int> vec; cout << "size = " << vec.size() << " capacity = " << vec.capacity() << endl; for(vector<string>::size_type ix = 0; ix != 10; ix++){ vec.push_back(ix); } cout << "after push_back 10..." << endl; cout << "size = " << vec.size() << " capacity = " << vec.capacity() << endl; vec.reserve(30); cout << "after reserve 30 ..." << endl; cout << "size = " << vec.size() << " capacity = " << vec.capacity() << endl; while(vec.size() != vec.capacity()){ vec.push_back(2); } cout << "after filling ..." << endl; cout << "size = " << vec.size() << " capacity = " << vec.capacity() << endl; vec.push_back(3); cout << "after push_back ..." << endl; cout << "size = " << vec.size() << " capacity = " << vec.capacity() << endl; return 0; }