C++ Primer Plus 书之--C++ vector模板类及常用方法和iterator简介

本文详细介绍了C++中的vector模板类,包括如何创建和使用vector,以及迭代器iterator的概念和用法。同时,文章还讨论了vector的一些关键方法,如push_back()、erase()、insert()、for_each()、random_shuffle()和sort(),并提供了多个示例展示这些方法的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值