文章目录

  • C++primer-学习心得-第九章-顺序容器
  • 9.1 顺序容器概述
  • 9.2 容器库概览
  • 1. 迭代器
  • 练习9.4
  • 2. 容器类型成员
  • 3.begin和end成员
  • 4.容器定义和初始化
  • 5. 赋值和swap
  • 6. 容器大小操作
  • 9.3 顺序容器操作
  • 1.添加元素
  • 练习9.18
  • 练习9.19
  • 练习9.20
  • 2.访问元素
  • 3.删除元素
  • 练习9.26
  • 4.特殊的forward_list操作
  • 练习9.27
  • 练习9.28
  • 5.改变容器大小
  • 6. 容器操作可能使迭代器失效
  • 练习9.31
  • 9.4 vector对象是如何增长的
  • 9.5 额外的string操作
  • 1.构造string的其他方法
  • 练习9.41
  • 2.其他改变string的方法
  • 练习9.43
  • 练习 9.44
  • 练习9.45
  • 练习9.46
  • 3.string搜索操作
  • 4.compare函数
  • 5.数值转换
  • 练习9.50
  • 9.6 容器适配器
  • 练习9.52


C++primer-学习心得-第九章-顺序容器

一个容器就是一些特定类型对象的集合。而顺序容器为我们提供了控制元素的存储和访问顺序的能力,这个顺序与元素加入容器的顺序有关。

9.1 顺序容器概述

下面列出了标准库中的顺序容器

  • vector:可变大小数组,支持快速随机访问。在尾部之外的位置插入或删除元素可能会很慢
  • deque:双端列表,支持快速访问。头尾部插入/删除速度很快
  • list:双向链表。只支持双向顺序访问。在list中任何位置插入/删除速度都很快
  • forward_list:单向链表。只支持单向顺序访问。在链表中任何位置插入/删除速度都很快
  • array:固定大小数组。支持快速随机访问。不能添加/删除元素
  • string:与vector类型,专门用于保存字符。随机访问快。尾部插入删除速度块

string和vector将元素保存在连续的内存空间中,所以 由元素下标来计算其地址的速度非常块,但在容器中间插入或删除元素就会非常耗时。而list和forward_list在任何位置插入或删除元素都很块,但不支持随机访问:访问一个元素需要遍历整个容器,而且这两种容器的额外内存开销也很大。

deque是一种更为复杂的数据结构。支持快速随机访问,在中间位置插入或删除元素的代价可能很高,但在两端插入或删除元素速度很快。

注意,forward_list没有size操作。

那么问题来了,当我们需要容器时选择哪个容器呢?

  • 通常情况下选择vector就行了,不用纠结
  • 根据需求来选择适合的容器
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
int main() {
	ifstream in("dic.txt");
	vector<string> file_text, dics;
	list<string> list_dics;
	if (in.is_open()) {
		string lines;
		while (getline(in,lines))
		{
			//cout << lines << endl;
			string str;
			for (auto c : lines) {
				if (isalpha(c)) {
					str += c;
				}
				else if (str.size() > 0) {
					//cout << str << endl;
					dics.push_back(str);
					list_dics.push_back(str);
					str = "";
				}
			}
		}
	}
/*
	for (auto c : dics) {
		
		if (list_dics.size() == 0)
			list_dics.push_back(c);
		else {
			auto it = list_dics.begin();
			for (int i = 0; i < list_dics.size(); i++,it++) {
				if (c >=*it) {
					list_dics.insert(it, c);
					break;
				}
			}
		}
		//cout << c << endl;
	}*/
	list_dics.sort();
	for (auto c : list_dics) {
		cout << c << endl;
	}
}

以上代码是用list按字典顺序存储从文件中读取的单词。

本来我在考虑怎么按字典顺序在list中插入单词,但后面发现list自带排序方法sort,直接调用sort就可以让他自动排序,可以排序是区分大小写的,这样就和字典顺序有区别了。

9.2 容器库概览

这里我们将介绍所有容器都使用的操作。通常每个容器都定义在一个头文件中,如deque定义在头文件deque中,list定义在头文件list中。容器均定义为模板类。顺序容器几乎可以保存任意类型的元素。元素本身可以是另一种容器。

下面是通用的容器操作:

  • iterator:容器的迭代器类型
  • const_iterator: 可以读取元素但不能修改元素的迭代器类型
  • size_type:带符号整数类型
  • difference_type:带符号整数类型
  • value_type:元素类型
  • reference:元素左值类型
  • const_reference
  • C c:默认构造器
  • C c1(c2):构造c2的拷贝c1
  • C c(b,e):构造c,将迭代器b和e指定的范围内的元素拷贝给c(array不支持)
  • C c(a,b,c,…):列表初始化c
  • c1=c2:c1中的元素替换为c2中的元素
  • c1={a,b,c,…}:c1中的元素替换为列表中的元素
  • a.swap(b):交换a,b中的元素
  • swap(a,b):同上
  • c.size():c中元素数量
  • c.max_size():c中可保存的最大元素数量
  • c.empty():判断c是否为空
  • c.insert(args):插入元素(各个容器的接口可能不同)
  • c.emplace(inits):用inits构造c中一个元素
  • c.erase(args):删除
  • c.clear():删除c中所有元素
  • ==,!= : 所有容器支持相等或不等运算
  • <,<=,>,>= : 无须关联容器不支持
  • c.begin(),c.end():指向c的首元素和尾元素位置的迭代器
  • c.cbegin(),c.cend():返回const_iterator
  • reverse_iterator:按逆序寻址元素的迭代器(以下都不支持forward_list)
  • const_reverse_iterator:不能修改元素的逆序迭代器
  • c.rbegin(),c.rend():返回c的尾元素和首元素之前位置的迭代器
  • c.crbegin(),c.crend():放回 const_reverse_iterator

1. 迭代器

迭代器范围:由一对迭代器表示,两个迭代器通常被称为begin和end,或者first和last。标记了容器中元素的范围。第二个迭代器last是指向尾元素之后的位置。这点也可以理解,(比如容器的迭代器c.end()表示的就是指向最后一个元素之后一个单位的位置的指针,这样的好处是方便我们遍历容器)。这种元素范围成为左闭合区间,标准数学描述为

[begin,end)

注意begin和end必须是同一容器的迭代器,且end指向的是begin之后的位置,也可以指向同一个位置。

这时有

  • 如果begin和end相等则范围为空
  • 不相等则范围至少包含一个元素,且begin指向第一个元素
  • 可以对begin递增若干次使得begin=end
练习9.4
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
int main() {
	vector<int> vi;
	for (int i = 0; i <= 100; i++)
		vi.push_back(i);
	int* beg = &(vi[20]), * en = &(vi[60]);
	bool tes = test(beg, en, 46);
	cout << tes << endl;
}

练习9.5

#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
int main() {
	vector<int> vi;
	for (int i = 0; i <= 100; i++)
		vi.push_back(i);
	int* beg = &(vi[20]), * en = &(vi[60]);
	int* tes = test(beg, en, 46);
	if (tes == nullptr)
		cout << "can not find" << endl;
	else
		cout << *tes << endl;

}

2. 容器类型成员

每个容器都定义了多种类型,还有类型别名,类型别名使得我们可以在不了解容器中元素类型的情况下使用它,如元素类型value_type,元素类型的引用reference或const_reference。

3.begin和end成员

分别是指向容器第一个元素和尾元素之后位置的迭代器,我们以及很熟悉了就不用再介绍了。

4.容器定义和初始化

  • C c
  • C c1(c2)
  • C c1=c2
  • C c{a,b,c,…}
  • C c={a,b,c,…}
  • C c(b,e)
  • C seq(n):不包括array的顺序容器的构造器才接受大小参数,seq包含n个元素
  • C seq(n,t):seq中包含n个初始化为值t的元素

对于array

array<int,42>;
array<string,10>;
array<int,10>::sizetype i;
array<int,10>ia1;
array<int,10>digits={0,1,2,3,4,5,6,7,8,9};
array<int,10>copy=digits;

5. 赋值和swap

  • c1=c2
  • c={a,b,c,…}
  • swap(c1,c2)
  • c1.swap(c2)
  • seq.assign(b,e) assign操作不适用关联容器和array
  • seq.assign(i1)
  • seq.assign(n,t)

6. 容器大小操作

我们直接看下面的实例

vector<int> v1={1,3,5,7,9,12};
vector<int> v2={1,3,9};
vector<int> v3={1,3,5,7};
vector<int> v4={1,3,5,7,9,12};
v1<v2//true   ->5<9
v1<v3//false   ->size
v1==v4//true
v1==v2//false

9.3 顺序容器操作

1.添加元素

下面这些操作array不支持,forward_list有自己版本的insert和emplace,forward_list不支持push_back和emplace_back

  • c.push_back(t)
  • c.emplace_back(args)
  • c.push_front(t)
  • c.emplace_front(t)
  • c.insert(p,t)
  • c.emplace(p,args)
  • c.insert(p,n,t):迭代器p指向的元素之前插入n个值为t的元素
  • c.insert(p,b,e):迭代器b,e范围内的元素插入到迭代器p指向的 元素前
  • c.insert(p,i1):i1为一个花括号括起来的元素值类型

其中,emplace操作是将参数传递给元素类型的构造器。

c.emplace_back("11111",25,15.99);
c.push_back(Sales_data("11111",25,15.99));
练习9.18
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;

int main() {
	deque<string> get;
	string str;
	while (cin >> str)
		get.push_back(str);
	for (auto it = get.begin(); it != get.end(); it++)
		cout << *it << endl;

}
练习9.19
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;

int main() {
	deque<string> get;
	list<string>get_list;
	string str;
	while (cin >> str)
		get_list.push_back(str);
	for (auto it = get_list.begin(); it != get_list.end(); it++)
		cout << *it << endl;

}
练习9.20
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;

int main() {
	list<int>ilist = { 1,2,3,4,5,6,7,8,9,10 };
	deque<int>d1, d2;
	for (auto c : ilist) {
		if (c % 2 == 0)
			d1.push_back(c);
		else
			d2.push_back(c);
	}
	cout << "c1:" << endl;
	for (auto c : d1)
		cout << c << endl;
	cout << "c2:" << endl;
	for (auto c : d2)
		cout << c << endl;

}

2.访问元素

每个顺序容器都有一个front成员函数和back(除了forward_list)成员函数,分别返回首元素和尾元素的引用。另外,*c[n]c.at(n)返回下表为n的元素的引用。

3.删除元素

array不支持,forward_list有特殊版本的erase且不支持pop_back;vector和string不支持pop_front

  • c.pop_back():删除尾元素
  • c.pop_front():删除首元素
  • c.erase§:删除迭代器p指向的元素,返回被删元素之后元素的迭代器
  • c.erase(b,e):删除b,e范围内的元素,返回最后被删元素之后元素的迭代器
  • c.clear():删除所有元素
练习9.26
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;

int main() {
	int ia[] = { 0,1,1,2,3,5,8,13,21,55,89 };
	vector<int>vi;
	list<int>li;
	for (auto c : ia) {
		li.push_back(c);
		vi.push_back(c);
	}
	auto vb = vi.begin();
	auto lb = li.begin();
	while (vb != vi.end()) {
		if (*vb % 2 == 0)
			vb = vi.erase(vb);
		else
			++vb;
	}
	while (lb != li.end()) {
		if (*lb % 2 == 1)
			lb = li.erase(lb);
		else
			++lb;
	}
	cout << "vector:" << endl;
	for (auto c : vi)
		cout << c << endl;
	cout << "list:" << endl;
	for (auto c : li)
		cout << c << endl;

}

4.特殊的forward_list操作

  • lst.before_begin():返回指向链表首元素之前的不存在的元素的迭代器
  • lst.cbefore_begin()
  • lst.insert_after(p,t):迭代器p之后插入元素
  • lst.insert_after(p,n,t)
  • lst.insert_after(p,b,e)
  • lst.insert_after(p,i1)
  • emplace_after(p,args)
  • lst.erase_after§:删除p指向的元素之后的元素,返回被删元素之后元素的迭代器
  • lst.erase_after(b,e)
练习9.27
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;

int main() {
	int ia[] = { 0,1,1,2,3,5,8,13,21,55,89 };
	forward_list<int>fi;
	for (auto c : ia)
		fi.push_front(c);
	auto it = fi.before_begin();
	auto itt = fi.begin();
	while (itt != fi.end()) {
		if (*itt % 2 == 1) {
			itt = fi.erase_after(it);
		}
		else {
			it = itt;
			itt++;
		}
	}
	for (auto c : fi)
		cout << c << endl;
}
练习9.28
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
void fun(forward_list<string>& fs, string s1, string s2) {
	auto bb = fs.before_begin();
	auto b = fs.begin();
	while (b != fs.end()) {
		if (*b == s1) {
			fs.insert_after(bb,1, s2);
			//cout << "------" << endl;
			return ;
		}
		else {
			bb = b;
			b++;
		}
	}
	fs.push_front(s2);
}

int main() {
	forward_list<string> ss = {"reo","reoreoreo","reoreoreoreo","reoreoreoreoreoreo"};
	fun(ss, "reoreoreo-", "The world");
	for (auto c : ss)
		cout << c << endl;
}

5.改变容器大小

resize不适用array

  • c.resize(n):若n<c.size(),则弃掉多余的元素
  • c.resize(n,t):新添加的元素初始化为t

6. 容器操作可能使迭代器失效

向容器添加元素后

  • 对于容器vector或string,若存储空间被重新分配,则相关的迭代器、指针和引用都将失效。如果存储空间未重新分配,则指向插入位置之前的元素的迭代器、指针和引用仍有效,指向之后的失效
  • 对于deque,插入到除首尾位置的任何位置都会导致失效。如果在首尾位置添加元素,迭代器失效,但指向存在元素的指针和引用有效。
  • 对于list和forward_list,有效

删除元素,指向被删元素的迭代器、指针和引用都失效。

  • 对于list和forward_list,其他位置的有效
  • 对于deque,首尾之外的位值的元素被删除,其他元素的也都失效。如果删除首尾元素,其他元素的有效
  • 对于vector和string,其他元素的有效
练习9.31
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
int main() {
	list<int>li = { 0,1,2,3,4,5,6,7,8,9 };
	forward_list<int>fli = { 0,1,2,3,4,5,6,7,8,9 };
	auto it = li.begin();
	while (it != li.end())
	{
		if (*it % 2) {
			it = li.insert(it, *it);
			++it; ++it;
		}
		else {
			it = li.erase(it);
		}
	}
	auto itt = fli.begin();
	auto ittt = fli.before_begin();
	while (itt !=fli.end())
	{
		if (*itt % 2) {
			itt = fli.insert_after(ittt, *itt);
			++itt;
			ittt = itt;
			++itt;
		}
		else {
			itt = fli.erase_after(ittt);
		}
	}
	for (auto c : li)
		cout << c << endl;
	cout << "---" << endl;
	for (auto c : fli)
		cout << c << endl;
}

9.4 vector对象是如何增长的

对于vector和string,我们知道,容器中元素是连续存储的,且容器大小是可变的,试想如果容器中的空间满了,此时再向其中添加新的元素又要保证连续存储,容器只能分配新的更大的空间并把原有的元素全部搬到新的空间中同时释放旧存储空间。如果每次添加新元素都需要重新分配空间,那性能将会很慢的,为此,标准库实现者的策略是当需要分配新的空间时给它分配比所需的空间更大的空间,这样一来,它的性能表现高效了很多,扩张操作通常比list和deque要快。

管理容器的成员函数

shrink_to_fit只适用于vector、string和deque

capacity和reserve只适用于vecor和string

  • c.shrink_to_fit():请将capacity减少为与size()相同大小
  • c.capacity():不重新分配内存空间的话,c可存储的元素数量
  • c.reserve():分配至少可以容纳n个元素的内存空间
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
int main() {
	vector<int>vi;
	for (int i = 0; i < 100; i++) {
		vi.push_back(i);
		cout << vi.capacity() << endl;
	}
	vi.shrink_to_fit();
	cout << vi.capacity() << endl;
}

9.5 额外的string操作

1.构造string的其他方法

  • string s(cp,n)
  • string s(s2,pos2)
  • string s(s2,pos2,len2)
const char *cp="Hello world!!!";
char nonull[]={'H','i'};
string s1(cp);
string s2(nonull,2);
string s3(s1,6);
string s4(s1,6,20);

substr操作返回一个string,它是原始string的一部分或全部的拷贝。

  • s.substr(pos,n):返回一个s中从pos开始的n个字符组成的字符串。pos默认为0,n默认为s.size()。
练习9.41
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
int main() {
	vector<char>chs = { 'T','h','e',' ','W','o','r','l','d' };
	char test[] = { 'T','h','e',' ','W','o','r','l','d' };
	string str;
	for (auto c : chs)
		str += c;
	string strs(str);
	string s1(test,size(test));
	cout << strs << endl;
	cout << s1 << endl;
}

2.其他改变string的方法

  • s.insert(pos,args):在pos之前插入args指定的字符,pos是下标时返回一个指向s的引用,pos是迭代器时返回指向第一个插入字符的迭代器
  • s.erase(pos,len):删除从pos开始的len个字符,len省略则删除从pos开始到s末尾的所有字符,返回一个指向s的引用
  • s.assign(args):替换
  • s.append(args):追加,返回指向s的引用
  • s.replace(rangs,args):范围rangs内的字符替换为args
    其中args可以是下列形式之一,append和assign可以是以下所有形式,而replace和insert允许的args依赖于range和range
  • str
  • str,pos,len
  • cp,len
  • cp
  • n,c
  • b,e
  • 初始化列表
练习9.43
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
void fun(string& s1, string old, string ne) {
	auto it = s1.begin();
	int pos = 0;
	while (it != s1.end()) {
		
		if (*it == *(old.begin())) {
			auto itt = it;
			auto oit = old.begin();
			int a = 0;
			while (oit != old.end()) {
				if (*oit == *itt)
					a++;
				itt++; oit++;
			}
			if (a == old.size()) {
				cout << "ok" << endl;
				--it;
				s1.erase(pos, old.size());
				++it;
				it=s1.insert(it, ne.begin(),ne.end());
			}
		}
		++it;
		++pos;//放后面
	}
}
int main() {
	string test = "test the program and thourgh";
	string str;
	fun(test, "thourgh", "thur");
	cout << test << endl;
}
练习 9.44
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
void fun(string& s1, string old, string ne) {
	auto it = s1.begin();
	int pos = 0;
	while (it != s1.end()) {

		if (*it == *(old.begin())) {
			auto itt = it;
			auto oit = old.begin();
			int a = 0;
			while (oit != old.end()) {
				if (*oit == *itt)
					a++;
				itt++; oit++;
			}
			if (a == old.size()) {
				cout << "ok" << endl;
				//--it;
				//s1.erase(pos, old.size());
				//++it;
				//it = s1.insert(it, ne.begin(), ne.end());
				s1.replace(pos, old.size(), ne);//pos,len,string
			}
		}
		++it;
		++pos;//放后面
	}
}
int main() {
	string test = "test the program and thourgh";
	string str;
	fun(test, "thourgh", "thur");
	cout << test << endl;
}
练习9.45
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
void fun(string& s1, string first, string last) {
	s1.insert(s1.begin(), first.begin(),first.end());
	s1.append(last);
}
int main() {
	string test = "Xie";
	string str;
	fun(test, "Mr.", "sir");
	cout << test << endl;
}
练习9.46
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;
void fun(string& s1, string first, string last) {
	s1.insert(0,first);
	s1.insert(s1.size(), last);
}
int main() {
	string test = "Xie";
	string str;
	fun(test, "Mr.", "sir");
	cout << test << endl;
}

3.string搜索操作

返回指定字符出现的下标,未找到则返回npos

  • s.find(args):args第一次出现的位置
  • s.rfind(args):最后一次出现的位置
  • s.rfind_first_of(args):args中任意一个字符第一次出现的位置
  • s.find_last_of(args):args中任意一个字符最后一次出现的位置
  • s.find_first_not_of(args):第一个不在args中的字符
  • s.find_last_not_of(args):最后一个不在args中的字符

其中args为以下形式之一

  • c,pos:从pos位置开始查找字符c,pos默认为0
  • s2,pos:从pos位置查找字符串s2
  • cp,pos:从pos位置开始查找指针cp指向的以空字符结尾的c风格字符串
  • cp,pos,n:从pos位置开始查找指针cp指向的数组的前n个字符
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

int main() {
	string test = "ab2c3d7R4E6";
	string str="0123456789";
	int a = test.find_first_of(str);
	int b = test.find_first_not_of(str);
	for (int i = 0; i < 10; i++) {
		cout << test.find_first_of(str[i]) << endl;
	}
	cout << a << " " << b << endl;
}
4.compare函数

s.compare的几种参数形式

  • s2
  • pos1,n1,s2
  • pos1,n1,s2,pos2,n2
  • cp
  • pos1,n2,cp
  • pos1,n1,cp,n2

5.数值转换

  • to_string(val)
  • stoi(s,p,b):返回s的起始子串的数值,b表示转换所用的基数(默认为10),p是size_t的指针
  • stol(s,p,b)
  • stou(s,p,b)
  • stoll(s,p,b)
  • stoull(s,p,b)
  • stof(s,p)
  • stod(s,p)
  • stold(s,p)
练习9.50
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>

using namespace std;

int main() {
	vector<string> nums = { "213","23423","234234" };
	int a = 0;
	for (auto c : nums) {
		a += stoi(c, 0);
		cout << stoi(c, 0)<<endl;
	}
	cout << a << endl;
}

9.6 容器适配器

除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue和priority_queue。一个适配器是一种机制,能使某种事物的行为看起来像另一种事物一样。如stack适配器接受一种顺序容器(除array和forward_list),并使其操作起来像stack一样。

下面列出所有适配器都支持的操作和类型

  • size_type
  • value_type
  • container_type
  • A a;
  • A a©;
  • 关系运算符
  • a.empty()
  • a.size()
  • swap(a,b)
  • a.swap(b)

栈适配器stack

stack类型定义在头文件stack中。栈默认基于deque实现,也可以在list和vector之上实现

栈操作

  • s.pop()
  • s.push(item)
  • s.emplace(args)
  • s.top()

如使用stack的一个简单的例子

#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>
#include<stack>
using namespace std;
void fun(string& s1, string old, string ne) {
	string str = "abcdefg";
	str.replace(2,2, "test");//pos,len
	cout << str << endl;
}

int main() {
	vector<string>sv = { "test","asdfasdf" };
	stack<string, vector<string>>str(sv);
	str.push("asdfasd");
	str.push("asdf");
	while (!str.empty()) {
		string a = str.top();
		str.pop();
		cout << a << endl;
	}
}

另外,看到习题9.52,题目意思上可能是让用stack判断一段(字符串形式的)表达式中是否有括号,如果有括号则去掉括号并将括号中的运算结果替换原表达式中括号中的内容,如果题目要求真是如此,那么这道题出得是有问题的作为这一小节后的习题来说,而且这样的难度也大大增加了。我个人猜测(结合这本书的英文原文)这道题考察的应该是:用stack检测一段字符串中是否有括号(存在左括号时有没有与之相匹配的右括号),有的话将括号弹出,最后得到没有括号的表达式。根据这个要求,我的解法如下:

练习9.52
#include<iostream>
#include<fstream>
#include<string>
#include<deque>
#include<list>
#include<forward_list>
#include<vector>
#include<array>
#include<stack>
using namespace std;

int main() {
	string str = "test(test)--(test)--((test))";
	stack<char, string>stst(str),stt,ss,sss;
	bool has = false;
	while (!stst.empty()) {
		char a = stst.top();
		//cout << a << endl;
		if (a == ')' && !has) {
			has = true;
			}else if(has && a!='('){
				stt.push(a);
				cout << a << endl;
			}
			else if (has && a == '(') {
			has = false;
			while (!stt.empty()) {
				sss.push(stt.top());
				stt.pop();
			}
			while (!sss.empty()) {
				ss.push(sss.top());
				sss.pop();
			}
		}else if (!has) {
			ss.push(a);
			}
		
		stst.pop();
	}
	string s;
	while (!ss.empty()) {
		char a = ss.top();
		s += a;
		ss.pop();
	}
	cout << s << endl;
}

另外,还可以参考一位大佬对这个问题的看法

队列适配器queue

queue和priority_queue定义在queue头文件中。queue默认基于deque实现,也可用于list或vector,priority_queue默认基于vector实现,也可用deque实现

  • q.pop()
  • q.front()
  • q.back()
  • q.top()
  • q.push(item)
  • q.emplace(args)