C++ 小白 学习记录9

大神请忽略~

顺序容器

通常情况下vector是个不错的选择.

容器的公共操作

迭代器范围

左闭合区间 [begin, end), beigin包含, end不包含. end指向最后一个元素的后一个位置.

左闭合范围的特点:

  • 如果begin==end, 则范围为空
  • 如果begin !=end 则范围至少包含一个元素, 且begin指向该范围中的第一个元素
  • 可以 ++begin , 然后begin==end

begin(), rbegin() 反向迭代器第一个元素, cbegin() const迭代器

auto与begin, end 结合时, 获得的迭代器是否是const取决于容器的类型, 而c开头的begin,end等一定能获得const版本的迭代器.

当两个容器发生拷贝时, 两个容器的类型和元素类型都必须相同, 如果是使用迭代器, 则只需要元素能够转化即可.

array 42个int类型的数组. array必须同时指定元素的类型和大小. 其大小为array::size_type i;

默认构造的array是非空的, 它包含了与其大小一样多的元素.

    array a = {0, 1, 2};
    int b[3] = {0,1,2};

不能对内置数组进行拷贝或对象赋值, 但是array可以.

	array<int, 3> a = {0, 1, 2};
	int b[3] = {0,1,2}; // 正确
	int b2[3] = b; // 错误 不能复制
	array<int, 3>a2 = a; // 正确
	int c[3]; // 未指定数组内每个数的初值, 值未知
	c[3] = { 2 }; // 内存越界

赋值和swap  swap(c1,c2)交换c1, c2中的元素,比从c2向c1拷贝快得多.

	array<int, 3> a1 = { 1,2,3 };
	array<int, 3> a2 = { 123 };// 11中 所有元素均为123, 14中 第一个元素123, 其余为0
	a1 = a2;
	a2 = { 3, 2 }; // 11中 错误不能将一个花括号列表赋值给数组; 14中可以, 第一个元素为3, 其余为0
	for (auto a : a2) cout << "a2: " << a;

seq.assign(b,e) 将seq中的元素替换为迭代器b和e所表示的范围中的元素.

seq.assign(il) 将seq中的元素替换为初始化列表il中的元素

seq.assign(n,t) 将seq中的元素替换为n个值为t的元素.

赋值相关运算会导致指向左边容器内部的迭代器,引用和指针失效. 而swap操作将容器内容交换不会导致迭代器, 引用和指针失效(除了array和string)

assign 与赋值运算符的区别:

assign允许一个不同但相容的类型赋值,或者从容器的一个子序列赋值.

swap 只交换容器的内部数据结构  除了array. 迭代器,引用,指针不会失效 除string

最好统一使用非成员版本的swap

容器大小

  • size  元素的个数
  • empty  当size==0 时 返回true, 否则false
  • max_size  返回一个大于或等于该类型容器所能容纳的最大元素数.

关系运算符

每个容器类型都支持 ==和!=, 无序关联容器以外的所有容器都支持<, <=, >, >=

容器类型不同不能比较, 如vector 和list, 需要编程逐一比较.

顺序容器的操作

容器的特定位置 插入元素 

xx.insert(xx.begin(), "hello") 

插入范围内元素

 xx.insert(xx.begin(), 10, "hello"), xx.insert(xx.begin(), v.end()-2, v.end())

xx.insert(xx.end(), {1,2,3,4})

insert 返回指向第一个新加入元素的迭代器.

emplace_front, emplace, emplace_back , 对应 push_front, insert, push_back.

emplace 和insert的区别:

  • push/insert 将元素类型的对象传递进去, 这些对象被拷贝到容器中. 会创建临时对象, 然后放入容器
  • emplace 则是将参数传递给元素类型的构造函数.在容器内存空间中直接构建新对象

访问元素

在解引用一个迭代器或调用front或back之前检查是否有元素c.empty()

front,  back(forward_list 不支持)  必须确保容器不能为空. 其返回值为引用.

string vector deque array支持下标的容器 可以使用at. at在编译时检查下标是否越界, 而[] 不会.

删除元素

删除元素不使用array.

forward_list 不支持pop_back, vector和string 不支持pop_front

c.erase(p) 删除迭代器p指定的元素.

c.erarse(b,e) 删除迭代器b, e指定范围的元素.

c.clear() 删除所有元素

deque删除除首尾之外的任何元素都会使所有迭代器,引用和指针失效

vector, string 删除点之后的迭代器,引用和指针都会失效

forward_list:

before_begin(), cbefore_begin(),

insert_after(p, t), insert_after(p, n, t) p 之后插入n个t

insert_after(p,b,e)  插入另一个迭代器b,e之间的元素

insert_after(p, il) 插入列表il {}

emplace_after(p, args)

erase_after(p) 删除p之后的元素

erase_after(b,e) 删除[b, e)之间的元素

改变容器大小(除了array)

如果变小, 则后面的元素被删除, 如果变大, 会被放到容器后部分.

c.resize(n), c.resize(n, t)  使用t初始化新添加的元素, c调整为n个元素.

如果元素不能默认初始化,必须提供默认构造函数.

迭代器失效的情况- 插入:

  • vector和string, 指向插入点之后
  • deque, 插入两端之外的地方, 整个都失效,  插入两端,两端的失效

迭代器失效的情况- 删除:

  • 指向被删除的都会失效
  • deque 首尾之外删除 都会失效, 如果删除尾, 尾后迭代器失效, 如果是首, 不受影响.
  • vector, string 指向被删之后的会失效.

vector, string, deque, 如果对容器插入/删除要小心使用迭代器

advance(it, n) 移动迭代器向前n个位置.

vector 对象是如何增长的

vector会预留部分空间以免在频繁插入时频繁的重新申请空间,从而可以加快执行速度.

管理容器的成员函数

c.shrink_to_fit()  将capacity()减少为与size()相同的大小, 不保证退还多余的内存.

c.capacity() 不重新分配内存空间的话, c可以保存多少元素

c.reserve(n) 分配至少能容纳n个元素的内存空间

额外的string操作

const char *cp ="hello world!"

char noNull[] = {'h', 'e'};

string s1(noNull) //报错, noNull 没有以空字符结尾

substr 返回一个截取的字符串

搜索操作  都返回string::size_type值, 找不到返回const string::size_type 类型的npos, 并初始化值为-1;

find 大小写敏感 

查找与给定字符串中任何一个字符匹配的位置.

string numbers("0123456789"),  name("r2d2");

auto pos = name.find_first_of(numbers); // pos = 1,  name 中第一个数字的下标.

string dept("03714p3");

auto pos = dept.find_first_not_of(numbers);  // pos = 5, 字符p的下标, 第一个不在参数中的字符.

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

args的形式:

  • c,pos 从pos开始查找字符c, pos默认0
  • s2, pos, 从pos查找字符串s2, pos 默认0
  • cp,pos 从pos开始查找指针cp指向的以空字符串结尾的c风格字符串, pos默认0
  • cp, pos, n 从pos开始查找指针cp指向的数组的前n个字符, pos和n 无默认值.

compare函数

  • s1.compare(s2) 与字符串s2比较
  • s1.compare(pos1, n1, s2)  s从pos1开始的n1个字符与s2比较
  • s1.compare(pos1, n1, s2, pos2, n2) s从pos1开始的n1个字符与s2中从pos2开始的n2个字符比较
  • s1.compare(cp) s与cp指向的以空字符结尾的字符数组比较
  • s1.compare(pos1, n1, cp) s中pos1开始的n1个字符与cp指向的以空字符结尾的字符数组比较
  • s1.compare(pos1,n1,cp,n2) s中pos1开始的n1个字符与cp指向的以空字符结尾的n2个字符比较

数值转换

数值数据与标准库string之间的转换

  • to_string(val) 返回数值val的string表示.
  • stoi(s,p,b)  返回int, long, unsigned long, long long, unsigned long long. b是基数(8, 10, 16), p是size_t
  • stol(s,p,b)  指针,用来保存s中第一个非数值字符的下标, 默认为0
  • stoll(s,p,b)
  • stoull(s,p,b)
  • stof(s,p)
  • stod(s,p)
  • stold(s,p)

容器适配器

为了简化容器的操作???

stack, queue, priority_queue

  • size_type 一种类型, 足以保存当前类型的最大对象的大小
  • value_type 元素类型
  • container_type 实现适配器的底层容器类型
  • A a  创建一个名为a的空适配器
  • A a(c); 创建一个名为a的适配器, 带有容器c的一个拷贝
  • 关系运算符  ==, !=, <=, <, >, >=
  • a.empty() 若a包含任何元素 返回false, 否则 true
  • a.size() 返回a中的元素数目
  • swap(a,b)  交换a和b的内容
  • a.swap(b)

stack push_back,pop_back, back,  不能使用array forward_list

queue back, push_back, front, push_front   可以用于list和deque, 不能vector

priority_queue front, push_back, pop_back 随机访问 , 能用于vector和deque, 不能list

栈适配器stack的操作:

  • s.pop()  删除栈顶元素, 不返回该元素值
  • s.push(item) 创建一个新元素压入栈顶, 拷贝方式
  • s.emplace(args) 有args构建新元素
  • s.top() 返回栈顶元素, 但不将元素弹出栈.

队列适配器操作: 所有操作都不删除元素

queue默认基于deque实现, priority_queue(可以设定优先级)默认基于vector实现. 先进先出原则

  • q.pop() 返回queue的首元素, 或者priority_queue的最高优先级元素, 不删除元素
  • q.front() 返回首元素或尾元素, 不删除元素
  • q.back() 只适用于 queue
  • q.top() 返回最高优先级元素 不删除元素
  • q.push(item) 在queue末尾或priority_queue恰当的位置 创建一个元素
  • q.emplace(args)

9.6 的联系题比较难, 真没想到一个带小括号的四则运算就这么难处理.

几乎照抄了这位兄弟的实例 https://blog.csdn.net/qq_43152052/article/details/96333433,

int priority2(const char opt) {
	if ('(' == opt) return 1;
	if ('+' == opt || '-' == opt) return 2;
	if ('*' == opt || '/' == opt) return 3;
	return 0;
}
void calculate2(stack<int>& opdstack, const char opt)/*计算操作数栈的结果*/
{
	int a = opdstack.top();	//取栈顶元素a
	opdstack.pop();
	int b = opdstack.top();	//取栈顶元素b
	opdstack.pop();

	if (opt == '+')
	{
		opdstack.push(a + b);		//压入a+b的值
	}
	if (opt == '-')
	{
		opdstack.push(b - a);	//压入b-a的值
	}
	if (opt == '*')
	{
		opdstack.push(a * b);	//压入a*b的值
	}
	if (opt == '/')
	{
		opdstack.push(b / a);	//压入b/a的值
	}
}
int caleExpression2(string str) {
	stack<int> stack_nums;
	stack<char> stack_operator;
	for (auto i = 0; i != str.length(); ++i) {
		char char_opt = str[i];
		if (char_opt == '+' || char_opt == '-' || char_opt == '*' || char_opt == '/') {
			if (stack_operator.size() == 0) //操作符栈为空
				stack_operator.push(char_opt);
			else {
				int curr_priority = priority2(char_opt);
				int stack_top_priority = priority2(stack_operator.top());
				if (curr_priority > stack_top_priority) {
					stack_operator.push(char_opt);
				}
				else {
					while (curr_priority <= stack_top_priority) {
						
						calculate2(stack_nums, stack_operator.top());
						stack_operator.pop(); //删除处理过的运算符
						if (stack_operator.size() > 0) {
							stack_top_priority = priority2(stack_operator.top());
						}
						else break;
					}
					stack_operator.push(char_opt);
				}
			}
			

		}
		else if (char_opt == '(') {
			stack_operator.push(char_opt);
		}
		else if (char_opt == ')') {
			// 出栈操作
			while (stack_operator.top() != '(') {
				calculate2(stack_nums, stack_operator.top());
				stack_operator.pop(); // 删除操作符
			}
			stack_operator.pop(); // 删除最后的 '('
		}
		else {
			// 如果是操作数, 就压入到操作数栈
			stack_nums.push(atoi(&char_opt));
		}

	}
	while (stack_operator.size() != 0) {
		calculate2(stack_nums, stack_operator.top());
		stack_operator.pop();
	}
	return stack_nums.top();
}

int main(int argc, char** argv) {

	//9.52
	string source = "(2*4+1)*2/(3-2)-1";// "(1+3)*3/(2-1)";
	vector<string> tokens = { "(","2", "*", "4", "+", "1",")", "*", "2", "/", "(","3", "-", "2",")", "-", "1" };// { "(", "1", "+", "3", ")", "*", "3", "/", "(", "2", "-", "1", ")" };
	for (auto i = 0; i != source.size(); ++i)
		cout << source[i];
	cout << endl;
	cout << caleExpression2(source) << endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yutao1131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值