使用vector模板
可使用<type>支出要存储的数据类型, 也可以使用初始化参数来指出需要多少空间:
#include <vector>
using namespace std;
// 含有5个int的vector
vector<int> ratings(5);
int n;
cin >> n;
vector<double> scores(n);
创建vector对象后, 可以使用数组表示法来访问各个元素:
ratings[9] = 9;
for(int i = 0; i < n; i++)
cout << scores[i] << endl;
来看一个完整的例子:
// vectordemo.cpp
#include <iostream>
#include <string>
#include <vector>
const int NUM = 5;
int main()
{
using std::vector;
using std::string;
using std::cin;
using std::cout;
using std::endl;
vector<int> ratings(NUM);
vector<string> titles(NUM);
cout << "You will do exactly as told. You will enter " << NUM << " book titles and your ratings(0~10)." << endl;
int i;
for(i = 0; i < NUM; i++)
{
cout << "Enter title #" << i << ":";
getline(cin, titles[i]);
cout << "Enter your rating(0~10):";
cin >> ratings[i];
cin.get();
}
cout << "Thank you , Your entered the following" << endl << "Rating\tBook" << endl;
for(i = 0; i < NUM; i++)
{
cout << ratings[i] << "\t" << titles[i] << endl;
}
return 0;
}
程序运行结果为:
迭代器iterator
迭代器是一个广义指针. 实际上, 它可以使指针, 也可以是一个可对其执行类似指针的操作--如解除索引(operator*())和递增(operator++())--的对象
给vector的double类型规范声明一个迭代器:
vector<double>::iterator pd;
假设scores是一个vector<double>对象:
vector<double> scores;
则可以使用迭代器pd执行这样的操作:
// pd指向第一个元素
pd = scores.begin();
*pd = 22.3;
// 将pd指向下一个元素
++pd;
迭代器的行为就像是指针, 还有一点C++11自动类型推断对迭代器会很有用, 例如:
常规写法:
vector<double>::iterator pd = scores.begin();
但是也可以直接这么写:
auto pd = scores.begin();
如果我们要遍历vector里的所有内容可以这么写:
for(pd = scores.begin(); pd != scores.end(); pd++)
cout << *pd << endl;
这里end()成员函数标识超过结尾的位置.
所有容易都包含以上讨论的方法, vector模板类也包含一些只有某些STL容器才有的方法. 例如: push_back()是一个将元素添加到末尾的方法, 例如:
vector<double> scores;
double temp;
while(cin >> temp && temp >= 0)
scores.push_back(temp);
cout << "You entered " << scores.size() << " scores." << endl;
这样每次循环都给scores对象增加一个元素, 这样我们不用了解元素的个数, 就能直接向末尾添加元素.
erase()
erase()方法删除vector中给定区间的元素. 它接收两个迭代器参数, 第一个迭代器指向区间的起始位置, 第二个迭代器指向区间终止处的后一个位置. 例如:
scores.erase(scores.begin(), scores.begin() + 2);
这段代码删除的是前两个元素
insert()
insert()方法接受3个迭代器参数, 第一个参数指定了新元素插入的位置, 第二个和第三个参数定义了被插入区间, 例如:
vector<int> old_v;
vector<int> new_v;
...
old_v.insert(old_v.begin(), new_v.begin() + 1, new_v.end());
上述代码将new_v中除了第一个元素外的所有元素插入到old_v的第一个元素前面.
来看一个完整的例子:
// vect2.cpp
#include <iostream>
#include <string>
#include <vector>
struct Review {
std::string title;
int rating;
};
bool FillReview(Review & rr);
void ShowReview(const Review & rr);
int main()
{
using std::cout;
using std::vector;
using std::endl;
vector<Review> books;
Review temp;
while(FillReview(temp))
{
// 向books的末尾添加数据
books.push_back(temp);
}
int num = books.size();
if(num > 0)
{
cout << "Thank you. You entered the following: \n" << "Rating \t Book\n";
for(int i = 0; i < num; i++)
{
ShowReview(books[i]);
}
cout << "Reprising: \n" << "Rating \tBook\n";
vector<Review>::iterator pr;
for(pr = books.begin(); pr != books.end(); pr++)
ShowReview(*pr);
// 使用复制构造函数
vector<Review> oldlist(books);
if(num > 3)
{
// 删除两个元素
books.erase(books.begin() + 1, books.begin() + 3);
cout << "After erasure: " << endl;
for(pr = books.begin(); pr != books.end(); pr++)
ShowReview(*pr);
// 插入一个item
books.insert(books.begin(), oldlist.begin() + 1, oldlist.begin() + 2);
cout << "After insertion: " << endl;
for(pr = books.begin(); pr != books.end(); pr++)
ShowReview(*pr);
}
books.swap(oldlist);
cout << "Swapping oldlist with books: " << endl;
for(pr = books.begin(); pr != books.end(); pr++)
ShowReview(*pr);
} else {
cout << "Nothing entered, nothing gained." << endl;
}
return 0;
}
bool FillReview(Review & rr)
{
std::cout << "Enter book title (quit to quit): ";
std::getline(std::cin, rr.title);
if(rr.title == "quit")
return false;
std::cout << "Enter book rating: ";
std::cin >> rr.rating;
if(!std::cin)
return false;
while(std::cin.get() != '\n')
continue;
return true;
}
void ShowReview(const Review & rr)
{
std::cout << rr.rating << "\t" << rr.title << std::endl;
}
程序运行结果为:
for_each()
for_each()函数可用于很多容器类, 它接手3个参数, 前两个参数是定义容器中区间的迭代器, 最后一个参数是指向函数的指针(更准确的说最后一个参数是一个函数对象). for_each()函数将被指向的函数应用于容器区间中的各个元素. 被指向的函数不能修改容器元素的值, 例如:
vector<Review>::iterator pr;
for(pr = books.begin(); books.end(); ShowReview);
上述代码就可以替换常规的for循环:
for(pr = books.begin(); pr != books.end(); pr++)
ShowReview(*pr);
Random_shuffle()函数
Random_shuffle()函数接受两个指定区间的迭代器参数, 并随机排列该区间中的元素. 例如:
random_shuffle(books.begin(), books.end());
上述代码会将books中的所有元素重新随机排列
与可用于任何容器类的for_each不同, 该函数要求容器类允许随机访问.
sort()函数
sort()函数也要求容器支持随机访问, 该函数有两个版本, 第一个版本接受两个定义区间的迭代器参数, 并使用为存储在容器中的类型元素定义的<运算符, 对取件中的元素进行操作, 例如:
vector<int> coolstuff;
...
sort(coolstuff.begin(), coolstuff.end());
上述代码会将coolstuff的内容按尚需排序, 排序时使用内置的<运算符对值进行比较
如果容器元素是用户定义的对象, 则要使用sort(), 必须定义能够处理该类型的operator<()函数. 例如, 如果为Review提供了成员或非成员函数operator<(), 则可以对包含Review对象的vector进行排序.
bool operator<(const Review & r1, const Review & r2)
{
if(r1.title < t2.title)
return true;
else if(r1.title == r2.title && r1.rating < r2.rating)
return true;
else
return false;
}
有了这样的函数后, 就可以对包含Review对象(如books)的vector进行排序了:
sort(books.begin(), books.end());
sort()的另一个格式, 接受3个参数, 前两个参数也是指定区间的迭代器, 最后一个参数是指向要使用的函数的指针(函数对象), 而不是用于比较的operator<(). 返回值可转换为bool, false表示两个参数的顺序不正确. 例如:
bool WorseThan(const Review & r1, const Review & r2)
{
if(r1.rating < r2.rating)
return true;
else
return false;
}
有了这个函数后, 就可以使用下面的语句将包含Review对象的books, 按arting升序进行排列:
sort(books.begin(), books.end(), WorseThan);
来看一个完整的例子:
// vect3.cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
struct Review
{
std::string title;
int rating;
};
bool operator<(const Review & r1, const Review & r2);
bool worseThan(const Review & r1, const Review & r2);
bool FillReview(Review & rr);
void ShowReview(const Review & rr);
int main()
{
using namespace std;
vector<Review> books;
Review temp;
while(FillReview(temp))
books.push_back(temp);
if(books.size() > 0)
{
cout << "Thank you. You entered the following " << books.size() << " ratings:\n" << "Rating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
// 排序
sort(books.begin(), books.end());
cout << "Sorted by title:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end(), worseThan);
cout << "Sorted by rating:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
// 随机排序
random_shuffle(books.begin(), books.end());
cout << "After shuffling:\nRating\tBook\n";
for_each(books.begin(), books.end(), ShowReview);
} else {
cout << "No entries.";
}
cout << "Bye.\n";
return 0;
}
bool operator<(const Review & r1, const Review & r2)
{
if(r1.title < r2.title)
return true;
else if(r1.title == r2.title && r1.rating < r2.rating)
return true;
else
return false;
}
bool worseThan(const Review & r1, const Review & r2)
{
if(r1.rating < r2.rating)
return true;
else
return false;
}
bool FillReview(Review & rr)
{
std::cout << "Enter book title (quit to quit):";
std::getline(std::cin, rr.title);
if(rr.title == "quit")
return false;
std::cout << "Enter book rating: ";
std::cin >> rr.rating;
if(!std::cin)
return false;
while(std::cin.get() != '\n')
continue;
return true;
}
void ShowReview(const Review & rr)
{
std::cout << rr.rating << "\t" << rr.title << std::endl;
}
程序运行结果为:
基于范围的for循环(C++11)
先看一个简单的for循环
double prices[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
for(double x : prices)
cout << x << std::endl;
还可以使用for循环来使用指定的变量依次访问容器的每个元素, 例如:
for(auto x : books) ShowReview(x);
这行代码就相当于:
for_each(books.begin(), books.end(), ShowReview);
注意: 不同于for_each(), 基于范围的for循环可修改容器的内容, 诀窍是指定一个引用参数. 例如:
void InflateReview(Review & r) {r.rating++;}
可使用如下循环对books的每个元素执行该函数:
for(auto & x : books) InflateReview(x);