标签:
参考C++ primer.
vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和 string 对象一样,标准库负责管理存储元素的相关内存。我们把 vector 称为 容器 ,是因为它可以包含其他对象。一个容器中的所有对象都必须是同一种类型的。我们将在第 9 章更详细地介绍容器。
使用 vector 之前,必须包含相应的头文件。本书给出的例子,都是假设已作了相应的 using 声明:
#include <vector> using std::vector;
vector<int> ivec; // ivec holds objects of type int vector<Sales_item> Sales_vec; // holds Sales_items
//几种初始化 vector 对象的方式 vector <T > v1 ; vector 保存类型为 T 的对象。默认构造函数 v1 为空。 vector < T > v2 ( v1 ); v2 是 v1 的一个副本。 vector < T > v3 ( n , i ); v3 包含 n 个值为 i 的元素。 vector < T > v4 ( n ); v4 含有值初始化的元素的 n 个副本。
vector<int> ivec1; // ivec1 holds objects of type int vector<int> ivec2(ivec1); // ok: copy elements of ivec1 into ivec2 vector<string> svec(ivec1); // error: svec holds strings, not ints
vector<int> ivec4(10, -1); // 10 elements, each initialized to -1 vector<string> svec(10, "hi!"); // 10 strings, each initialized to "hi!"
关键概念: vector 对象动态增长
vector 对象(以及其他标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。因为 vector 增长的效率高,在元素值已知的情况下,最好是动态地添加元素。
正如第 4 章将介绍的,这种增长方式不同于 C 语言 中的内置数据类型,也不同于大多数其他编程语言的数据类型。特别地,如果读者习惯了 C 或 Java 的风格,由于 vector 元素连续存储,可能希望最好是预先分配合适的空间。但事实上,为了达到连续性, C ++ 的做法恰好相反,具体原因将在第 9 章探讨。
虽然可以对给定元素个数的 vector 对象预先分配内存,但更有效的方法是先初始化一个空 vector 对象,然后再动态地增加元素(我们随后将学习如何进行这样的操作)。
2. 值初始化
如果没有给出元素的初始化式,那么标准库将提供一个 值初始化的 ( value initialized )元素初始化式。这个由库生成的初始值用于初始化容器中的每个元素。而元素初始化式的值取决于存储在 vector 中元素的数据类型。
如果 vector 保存内置类型(如 int 类型) 的元素,那么标准库将用 0 值创建元素初始 化值:
vector<string> fvec(10); // 10 elements, each initialized to 0
习题 3.11 下面哪些 vector 定义不正确? ( a ) vector < vector < int > > ivec ; ( b ) vector < string > svec = ivec ; ( c ) vector < string > svec ( 10 ,” null ”);
解答: (b)不正确。因为svec 定义为保存string 对象的vector 对象,而ivec 是 保存vector <int>对象的vector 对象(即ivec 是vector 的vector),二者 的元素类型不同,所以不能用ivec 来初始化svec。
习题 3.12 下列每个 vector 对象中元素个数是多少?各元素的值是什么? (a) vector<int> ivec1; (b) vector<int> ivec2(10); (c) vector<int> ivec3(10,42); (d) vector<string> svec1; (e) vector<string> svec2(10); (f) vector<string> svec3(10,”hello”);
解答: (a) 元素个数为0。 (b) 元素个数为10,各元素的值均为0。 (c) 元素个数为10,各元素的值均为42。 (d) 元素个数为0。 (e) 元素个数为10,各元素的值均为空字符串。 (f) 元素个数为10,各元素的值均为"hello"。
c.assign(beg,end)c.assign(n,elem) | 将[beg; end)区间中的数据赋值给c。将n个elem的拷贝赋值给c。 |
c.at(idx) | 传回索引idx所指的数据,如果idx越界,抛出out_of_range。 |
c.back() | 传回最后一个数据,不检查这个数据是否存在。 |
c.begin() c.end() |
传回迭代器中的第一个数据地址。 指向迭代器中末端元素的下一个,指向一个不存在元素。 |
c.capacity() | 返回容器中数据个数。 |
c.max_size() c.size() |
返回容器中最大数据的数量。 返回容器中实际数据的个数。 |
c.empty() | 判断容器是否为空。 |
c.erase(pos) |
删除pos位置的数据,传回下一个数据的位置。 删除[beg,end)区间的数据,传回下一个数据的位置。 移除容器中所有数据。 |
c.front() | 传回第一个数据。 |
get_allocator | 使用构造函数返回一个拷贝。 |
c.insert(pos,elem) c.insert(pos,n,elem) c.insert(pos,beg,end) |
在pos位置插入一个elem拷贝,传回新数据位置。 在pos位置插入n个elem数据。无返回值。 在pos位置插入在[beg,end)区间的数据。无返回值。 |
c.pop_back() | 删除最后一个数据。 |
c.push_back(elem) | 在尾部加入一个数据。 |
c.rbegin() | 传回一个逆向队列的第一个数据。 |
c.rend() | 传回一个逆向队列的最后一个数据的下一个位置。 |
c.resize(num) | 重新指定队列的长度。 |
c.reserve() | 保留适当的容量。 |
c1.swap(c2) swap(c1,c2) |
将c1和c2元素互换。同一个操作。 |
vector cvector c1(c2) vector c(n) ector c(n, elem) vector c(beg,end) |
创建一个空的vector。 |
c.~ vector () | 销毁所有数据,释放内存。 |
operator[] | 返回容器中指定位置的一个引用。 |
vector<int>::size_type // ok vector::size_type // error
// read words from the standard input and store them as elements in a vector string word; vector<string> text; // empty vector while (cin >> word) { text.push_back(word); // append word to text }
// reset the elements in the vector to zero for (vector<int>::size_type ix = 0; ix != ivec.size(); ++ix) ivec[ix] = 0;
C ++ 程序员习惯于优先选用 != 而不是 < 来编写循环判断条件。在上例中,选用或不用某种操作符并没有特别的取舍理由。学习完本书第二部分的泛型编程后,你将会明白这个习惯的合理性。
调用 size 成员函数而不保存它返回的值,在这个例子中同样不是必需的,但这反映了一个良好的编程习惯。在 C ++ 中,有些数据结构(如 vector )可以动态增长。上例中循环仅需要读取元素,而不需要增加新的元素。但是,循环可以容易地增加新元素,如果确实增加了新元素的话,那么测试已保存的 size 值作为循环的结束条件就会有问题,因为没有将新加入的元素计算在内。所以我们倾向于在每次循环中测试 size 的当前值,而不是在进入循环时,存储 size 值的副本。
我们将在第 7 章学习到, C ++ 中有些函数可以声明为内联( inline )函数。编译器遇到内联函数时就会直接扩展相应代码,而不是进行实际的函数调用。像 size 这样的小库函数几乎都定义为内联函数,所以每次循环过程中调用它的运行时代价是比较小的。
4. 下标操作不添加元素
初学 C ++ 的程序员可能会认为 vector 的下标操作可以添加元素,其实不然:
vector<int> ivec; // empty vector for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec[ix] = ix; // disaster: ivec has no elements
for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec.push_back(ix); // ok: adds new element with value ix
vector<int> ivec; // empty vector cout << ivec[0]; // Error: ivec has no elements! vector<int> ivec2(10); // vector with 10 elements cout << ivec[10]; // Error: ivec has elements 0...9
习题 3.13 读一组整数到 vector 对象,计算并输出每对相邻元素的和。如果读入元素个数为奇数,则提示用户最后一个元素没有求和,并输出其值。然后修改程序:头尾元素两两配对(第一个和最后一个,第二个和倒数第二个,以此类推),计算每对元素的和,并输出。
#include <iostream> #include <string> #include <vector> using namespace std; int main( ) { vector<int> vec; int n; while(cin>>n) vec.push_back(n); if(!vec.size()) { cout<<"没有数字!"<<endl; return -1; } for(vector<int>::size_type i=0; i<vec.size()-1; i+=2) { cout<<vec[i]+vec[i+1]<<"\t"; if((i+1)%6==0) cout<<endl; } if(vec.size()%2!=0) cout<<endl<<"最后一个数是:"<<vec[vec.size()-1]<<endl; system("PAUSE"); return 0; }
习题 3.14 读入一段文本到 vector 对象,每个单词存储为 vector 中的一个元素。把 vector 对象中每个单词转化为大写字母。输出 vector 对象中转化后的元素,每八个单词为一行输出。
#include <iostream> #include <vector> using namespace std; int main() { cout<<"输入一段文本(Ctrl + Z 结束):"<<endl; vector<string> vecStr; string word; while (cin>>word) { vecStr.push_back(word); } if (vecStr.size() == 0) { cout<<"没有输入字符串"<<endl; return -1; } for (vector<string>::size_type i = 0; i < vecStr.size(); i++) { for (string::size_type j = 0; j < vecStr[i].size(); j++) { vecStr[i][j] = toupper(vecStr[i][j]); } cout<<vecStr[i]<<" "; if ((i+1) % 8 == 0) { cout<<endl; } } return 0; }
习题 3.15 下面程序合法吗?如果不合法,如何更正? vector <int > ivec ; ivec [0] = 42 ;
解答: 不合法。因为ivec 是空的vector 对象,其中不含任何元素,而下标操作只 能用于获取已存在的元素。 更正:将赋值语句改为语句ivec.push_back(42);。
习题 3.16 列出三种定义 vector 对象的方法,给定 10 个元素,每个元素值为 42 。指出是否还有更好的实现方法,并说明为什么。
解答: 方法一: vector<int> ivec(10, 42); 方法二: vector<int> ivec(10); for (ix = 0; ix < 10; ++ix) ivec[ix] = 42; 方法三: vector<int> ivec(10); for (vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter) *iter = 42; 方法四: vector<int> ivec; for (cnt = 1; cnt <= 10; ++cnt) ivec.push_back(42); 方法五: vector<int> ivec; vector<int>::iterator iter = ivec.end(); for (int i = 0; i != 10; ++i) { ivec.insert(iter, 42); iter = ivec.end(); } 各种方法都可达到目的,也许最后两种方法更好一些。它们使用标准库中定义 的容器操作在容器中增添元素,无需在定义vector 对象时指定容器的大小,比 较灵活而且不容易出错。
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/djd1234567/article/details/48103609