算法入门到进阶(二)——STL和基本数据结构(vector和栈)


前言

这一篇博客主要是针对C++语言中的几个概念进行分析

  1. 容器
  2. 队列
  3. 链表
  4. set
  5. map

STL(Standerd Template Library)是C++的标准模板库,一些常用的数据结构,算法在STL中都有,熟练的掌握它们可以很方便的帮助我们编写代码。

STL包含容器(container)、迭代器(iterator)、空间配置器(allocator)、配接器(adapter)、算法(algorithm)、仿函数(functor)6个部分。这篇博客主要介绍容器和两个常用的算法。


容器

STL容器包括顺序式容器和关联式容器。

顺序式容器

顺序式容器包括vector、list、deque、queue、priority_queue、stack等,他们的特点如下。

  1. vector:动态数组,从末尾能快速插入与删除,直接访问任何元素
  2. list:双链表。从任何地方快速插入与删除。
  3. deque:双向列表,从前面或后面快速插入与删除,直接访问任何元素。
  4. queue:队列,先进先出。
  5. priority_queue:优先队列,最高优先级元素总是第一个出列
  6. stack:栈,后进先出。

关联式容器

  1. set:集合,快速查找,不允许重复值、
  2. multiset:快速查找,允许重复值。
  3. map:一对多映射,基于关键字快速查找,不允许重复值
  4. multimap:一对多映射,基于关键字快速查找,允许重复值。

Vector

数组是基本的数据结构,有静态数组和动态数组两种类型。一般在算法竞赛中,编码的惯例是:如果空间充足,能够用静态数组就用静态数组,而不用指针管理动态数组,这样编码比较简单并且不会出错;如果空间紧张,可以使用STL的vector建立动态数组,不仅节约空间,而且不易出错。

vector是STL的动态数组,在运行时能根据需要改变数组大小。由于它以数组形式存储,也就是说它的内存空间是连续的,所以索引可以在常数时间内完成。但是在中间进行插入和删除会造成内存块的复制。另外,如果数组后面的内存空间不够,需要重新申请一块足够大的内存。这些都会影响vector的效率.

vector容器是一个模板类,能存放任何类型的对象。

定义

如下表:
在这里插入图片描述用户还可以定义多维数组,例如定义一个二维数组:
vectora[MAXN];
它的一维大小是固定的MAXN,第二维是动态的。用这个方式可以实现图的邻接表存储。

常见操作

vector的常用操作如下表
在这里插入图片描述
在这里插入图片描述

案例:圆桌问题

圆桌边围坐着2n个人。其中n个是好人,另外n个是坏人。从第一个
人开始数,数到第m个人,立即赶走该人;然后从被赶走的人之后
开数,再数到的第m个人赶走,依此方法不断赶走围坐在圆桌边的
人。预先应如何安排这些好人与坏人的座位,才能使得在赶走n个人
之后圆桌边围坐的剩余的n个人都是好人?
输入:多组数据,每组数据输入:n,m<=32767
输出:对于每一组数据,输出2n个大写字母,"G"表示好人,
"B"表示坏人,50个字母为一行,不允许出现空白字符。
相邻数据间留有一个空行。
输入样例:
2 3
2 4
输出样例:
GBBG
BGGB

这个题目是约瑟夫问题。用vector模拟动态数组变化的圆桌,赶走n个人之后留下的都是好人

源码如下

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

int main() {
	vector<int> table;  //模拟圆桌
	int n, m;
	while (cin >> n >> m) {//输入好人数量,和数的次数
		table.clear();  //清空数组
		for (int i = 0; i < 2 * n; i++) {
			table.push_back(i); //初始化数组,在数组table后依次插入数值为i的元素
		}
		int pos = 0;//记录当前位置
		for (int i = 0; i < n; i++) {//开始数数,赶走n个人
			pos = (pos + m - 1) % table.size();//根据索引直接找到第m个人,
			//而圆桌是个环所以进行取余处理
			table.erase(table.begin() + pos);//赶走第pos个人,table人数减一
		}
		int j = 0;
		for (int i = 0; i < 2 * n; i++) {//打印预先安排座位
			if (!(i % 50) && i) {
				cout << endl;  //50个字母为1行
			}
			if (j < table.size() && i == table[j]) {//table留下的都是好人
				j++;
				cout << "G";
				//i==table[j]表示的意思就是,table[j]就是没有数到的好人,
				//等于i就是i这个位置表示好人输出"G",
				//而不是table[j]这个值的i自然就是坏人
			}
			else {
				cout << "B";
			}
		}
		cout << endl << endl;  //留一个空行
	}
	return 0;
}

运行结果:
在这里插入图片描述为了方便大家阅读我就放一个图片
在这里插入图片描述有点小 ,但是也无伤大雅。

注意:前面提到的,vector插入或删除中间某一项时需要线性时间,即需要把这个元素后面的所有元素往后移或前移,复杂度是O(n)。如果频繁移动,则效率很低。上面这个代码用了erase()来删除中间元素就有这个问题。

栈和stack

栈是基本的数据结构之一,特点是"先进后出"。例如乘坐电梯时,先进电梯的最后出电梯;一杯水,先倒进去的水是最后才出来的。

在C++中使用栈需要引入头文件
#include

栈相关的操作

  1. stacks; //定义栈,Type表示数据类型,例如int ,float,char等,s表示栈的名字
  2. s.push(item); //把item放到栈顶
  3. s.top(); //返回栈顶元素,但不会删除
  4. s.pop(); //删除栈顶元素,但不会返回。在出栈时需要进行两步操作,即先top()一哈,获得栈顶元素,再pop()删除栈顶元素
  5. s.size(); //返回栈中元素个数
  6. s.empty(); //返回栈是否为空,如果为空,返回ture,否则返回false

案例:字符串翻转

翻转字符串。例如输入"olleh! dlrow",输出"hello world!"。

源码

#include<iostream>
#include<stack>        
using namespace std;
int main() {

	int n;
	char ch;
	scanf_s("%d", &n);
	ch=getchar();//吸收换行符
	while (n--) {
		stack<char>s;  //定义栈
		while (true) {
			ch = getchar();//一次读取一个字符
			if (ch == ' ' || ch == '\n' || ch == EOF) {
				while (!s.empty()) {
					printf_s("%c", s.top());//输出栈顶
					s.pop();//清除栈顶
				}
				if (ch == '\n' || ch == EOF) {
					break;
				}
				printf_s(" ");
			}
			else {
				s.push(ch);//入栈
			}
		}
		printf_s("\n");
	}
	return 0;
}

运行结果
在这里插入图片描述
分析:
在这里插入图片描述

特别注意

爆栈问题。栈需要用空间存储,如果深度太大,或者存进栈的数组太大,那么总数会超过系统为栈分配的空间。这样就会爆栈,即栈溢出。其解决办法有以下两种:

  1. 在程序中调大系统的栈,这种方法依赖于系统和编译器。
  2. 手工写一个栈,自己设定。这部分后面的博客介绍

总结

相信通过上面的讲述和例子,你对C++的标准模板库中的vector容器和栈的操作和使用都有了清晰的认识。
对于两者记住,vector容器主要是针对动态数组问题的解决。而栈主要是对于有先进后出这个味道的问题适用。
下一篇博客分析队列和queue,优先队列和priority_queue以及链表和list

非常感谢大家的支持和点赞,这份认可是莫大的鼓励,也非常希望这些博客能对你学习计算机有帮助。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jacky~~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值