Chapter 9. Sequential Containers

vector    Flexible-size array.Supports fast random access.在尾部之外的位置插入或删除元素可能很慢。


string     A specialized container,similar to vector,that contains characters.

                   Fast random access,Fast insert/delete at the back.在尾部插入删除快。


deque   Double-ended queue.双端队列。Supports fast random access.Fast insert/delete at front or back.

                 在头尾插入元素很快

list       Doubly linked list.双向链表。Supports only bidirectional sequential access.只支持双向顺序访问。

                 Fast insert/delete at any point in the list.


array     Fixed-size array,固定大小数组。


The new library containers are dramatically faster than in previous releases.Modern C++ programs should use the library containers rather than more primitive structures like arrays.


• Unless you have a reason to use another container, use a vector.
• If your program has lots of small elements and space overhead matters, don’t use list or forward_list.

• If the program requires random access to elements, use a vector or a deque.

• If the program needs to insert or delete elements at the front and the back, but not in the middle, use a deque.


练习9.2: 定义一个list对象,其元素类型是intdeque.

std::list<std::deque<int>> ldi;


练习9.6:

What is wrong with the following program? How might you correct it?
list<int> lst1;
list<int>::iterator iter1 = lst1.begin(), iter2 = lst1.end();
while (iter1 < iter2) /*ERROR: operator< can't be applied to iterator for list*/

Fixed:

while(iter1 != iter2)

练习9.7:

//为了索引int的vector中的元素,应该使用什么类型?
//What type should be used as the index into a vector of ints ?
vector<int>::size_type

练习9.8:

What type should be used to read elements in a list of strings ? To write them ?
list<string>::iterator || list<string>::const_iterator  // read
list<string>::iterator                                 // write
string::const_iterator b;//b是只读。如果vector对象或string对象是一个常量,只能使用const_iterator
9.2.3  begin和end成员

list<string> a = {"Milton", "Shakespeare", "Austen"};
auto it1 = a.begin(); // list<string>::iterator
auto it2 = a.rbegin(); // list<string>::reverse_iterator
auto it3 = a.cbegin(); // list<string>::const_iterator
auto it4 = a.crbegin();// list<string>::const_reverse_iterator

C++11支持auto

// type is explicitly specified
list<string>::iterator it5 = a.begin();
list<string>::const_iterator it6 = a.begin();
// iterator or const_iterator depending on a's type of a
auto it7 = a.begin(); // const_iterator only if a is const
auto it8 = a.cbegin(); // it8 is const_iterator


得意  Best Practices

When write access is not needed, usecbegin andcend.

当不需要写访问时,应使用cbegincend.

练习9.9:

What is the difference between the begin and cbegin functions?

cbegin is a const member that returns the container’s const_iterator type.

begin is nonconst and returns the container’s iterator type.

练习9.10:

//What are the types of the following four objects ?
vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin();
auto it2 = v2.begin(),it3 = v1.cbegin(), it4 = v2.cbegin();

it1 is vector<int>::iterator

it2,it3 and it4 are vector<int>::const_iterator


array<int, 42> // type is: array that holds 42 ints
array<string, 10> // type is: array that holds 10 strings

练习9.14:

Write a program to assign the elements from a list of
char* pointers to C-style character strings to a vector of strings.

编写一个程序,将一个list中的char*指针(指向C风格字符串)元素赋值给一个vector中的string。

	list<const char*> l{ "Mooophy", "pezy", "Queeuqueg" };
	vector<string> v;
	v.assign(l.cbegin(), l.cend());
练习9.16:

判定两个vector<int>是否相等

#include <iostream>
#include <vector>

int main()
{
	std::vector<int> vec1{ 1, 2, 3, 4, 5 };
	std::vector<int> vec2{ 1, 2, 3, 4, 5 };
	std::vector<int> vec3{ 1, 2, 3, 4 };

	std::cout << std::boolalpha << (vec1 == vec2) << std::endl;//输出true
	std::cout << std::boolalpha << (vec1 == vec3) << std::endl;//输出false
	system("pause");
	return 0;
}
练习9.16:

比较list<int>中的元素和vector<int>中的元素

#include <iostream>
#include <vector>
#include <list>
using std::list;
using std::vector;
using std::cout;
using std::endl;
using std::boolalpha;

int main()
{
	list<int> list{ 1, 2, 3, 4, 5 };
	vector<int> vec1{ 1, 2, 3, 4, 5 };
	vector<int> vec2{ 1, 2, 3, 4 };

	cout << boolalpha<< (vector<int>(list.begin(), list.end()) == vec1)<< endl;//输出true
	cout << boolalpha<< (vector<int>(list.begin(), list.end()) == vec2)<< endl;//输出false
	system("pause");
}

P307
	vector<string> svec;
	list<string> slist;
	slist.insert(slist.begin(), "Hello!");// equivalent to calling slist.push_front("Hello!");
	svec.insert(svec.begin(), "Hello!");
	// no push_front on vector but we can insert before begin()
	//vector不支持push_front
	// warning: inserting anywhere but at the end of a vector might be slow
	//插入到vector末尾之外的任何位置都可能很慢

惊讶 Warning
It is legal to insert anywhere in a vector,deque, or string . However,doing so can be an expensive operation.



插入范围内元素

	vector<string>v = {"quasi","simba","frollo","Anna","Bruce Luu"};
	list<string>slist = { "A","B","C","D","E" };

	slist.insert(slist.begin(), v.end() - 2, v.end());
	for (auto i : slist)
		cout << i << " ";
	cout << endl;
	slist.insert(slist.end(), { "These","words","will","go","at","the","end" });
	for (auto i : slist)
		cout << i << " ";
	cout << endl;
程序运行:



C++11:

在新标准下,接受元素个数或范围的insert版本返回指向第一个新加入元素的迭代器。

Under the new standard, the versions ofinsert that take a count or a range return an iterator to the first element that was inserted.例如:We can use the value returned byinsert to repeatedly insert elements at a specified
position in the container:

使用insert的返回值

list<string> 1st;
auto iter = 1st.begin();
while (cin >> word)
iter = 1st.insert(iter, word); // same as calling push_front
第一次调用 insert会将读入的word插入到iter所指向的元素之前的位置。 insert返回的迭代器恰好指向这个新元素。将此迭代器赋予iter并重复循环。

Before the loop, we initializeiter to 1st.begin(). The first call to insert takes the string we just read and puts it in front of the element denoted byiter. The value returned byinsert is an iterator referring to this new element. We assign that iterator toiter and repeat the while, reading another word. As long as there are words to insert, each trip through thewhile inserts a new element ahead ofiter and reassigns toiter the location of the newly inserted element. That element is the (new) first element. Thus, each iteration inserts an element ahead of the first element in thelist.

练习9.18: 从标准输入中读取string序列,存入deque,编写一个循环,用迭代器打印deque的元素。

deque<string> input;
    for (string str; cin >> str; input.push_back(str))
        ;
    for (auto iter = input.cbegin(); iter != input.cend(); ++iter)
        cout << *iter << endl;

练习9.19: 重写上题程序,用list代替deque。

	list<string> input;
	for (string str; cin >> str; input.push_back(str));
	for (auto iter = input.cbegin(); iter != input.cend(); ++iter)
		cout << *iter << endl;
练习9.20: 奇数偶数分开放入deque.

我的烂代码:

	list<int>a = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,66,77 };
	deque<int>j = {};
	deque<int>o = {};
	for (auto i : a)
	{
		if (i % 2 == 0)
			o.push_back(i);
		else
			j.push_back(i);
	}
	for (auto i : j)
		cout << i << "  ";
	cout << endl;
	for (auto i : o)
		cout << i << "  ";
	cout << endl;
别人的代码:

	list<int> l{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	deque<int> odd, even;
	for (auto i : l) (i & 0x1 ? odd : even).push_back(i);//0x1是什么鬼!?
	for (auto i : odd) cout << i << " ";
	cout << endl;
	for (auto i : even) cout << i << " ";
	cout << endl;


练习9.22:看不懂

#include <iostream>
#include <vector>
using std::vector;

void insertDoubleValue(vector<int>& iv, int some_val)
{
	auto cursor = iv.size() / 2;
	auto iter = iv.begin(), mid = iv.begin() + cursor;
	while (iter != mid) {
		if (*iter == some_val) 
		{
			iter = iv.insert(iter, 2 * some_val);
			++iter;
			++cursor;
			mid = iv.begin() + cursor;
		}
		++iter;
	}
}

void print(const vector<int>& iv)
{
	for (auto i : iv) std::cout << i << " ";
	std::cout << std::endl;
}

int main()
{
	vector<int> iv = { 1, 1, 1, 1, 1, 7, 1, 9 };
	insertDoubleValue(iv, 1);
	print(iv);
	system("pause");
}


c.back()     返回c中尾元素的引用

c.front()     返回c中首元素的引用

	vector<int>c = {1,2,3,4,5,6,7};

		if (!c.empty())
		{
			auto va1 = *c.begin();//输出1
			auto va2 = c.front();//输出1
			auto last = c.end();
			auto val3 = *(--last);//输出7
			auto val4 = c.back();//输出7
			std::cout << va1 << "," << va2 << "," << val3 << "," << val4 << std::endl;
		}
if (!c.empty()) {
c.front() = 42; // assigns 42 to the first element in c
auto &v = c.back(); // get a reference to the last element
v = 1024; // changes the element in c
auto v2 = c.back(); // v2 is not a reference; it's a copy of c.back()
v2 = 0; // no change to the element in c
}
vector<int>c = { 1,2,3,4,5,6,7 };
cout << c.at(1);//输出2
slist.clear(); // delete all the elements within the container
slist.erase(slist.begin(), slist.end()); // equivalent
c.pop_back()      删除最后一个元素
c.erase(b,e)       删除迭代器b和e之间的元素

练习9.26: 

#include <iostream>
#include <vector>
#include <list>

using std::vector;
using std::list;
using std::cout;
using std::endl;
using std::end;

int main()
{
	int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };

	//! init
	vector<int> vec(ia, end(ia));
	list<int> lst(vec.begin(), vec.end());

	//! remove odd value
	for (auto it = lst.begin(); it != lst.end();)
		if (*it & 0x1)
			it = lst.erase(it);
		else
			++it;

	//! remove even value
	for (auto it = vec.begin(); it != vec.end();)
		if (!(*it & 0x1))
			it = vec.erase(it);
		else
			++it;

	//! print
	cout << "list : ";
	for (auto i : lst) cout << i << " ";
	cout << "\nvector : ";
	for (auto i : vec) cout << i << " ";
	cout << std::endl;
	system("pause");
	return 0;
}
	vector<int> vi = { 0,1,2,3,4,5,6,7,8,9 };
	auto iter = vi.begin();           // call begin, not cbegin because we're changing vi
		while (iter != vi.end()) 
		{
			if (*iter % 2) 
			{
				iter = vi.insert(iter, *iter); // duplicate the current element
					iter += 2; // advance past this element and the one inserted before it
			}
			else
				iter = vi.erase(iter); // remove even elements
									   // don't advance the iterator; iter denotes the element after the one we erased
		}//vi变为{1,1,3,3,5,5,7,7,9,9}
erase返回的迭代器指向下一个元素








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值