IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构3-栈和队列的操作 -> 正文阅读

[数据结构与算法]数据结构3-栈和队列的操作


一.栈和队列

1.栈stack

????栈stack是一种特殊的数据结构,它的逻辑结构和线性表相同,但是他的运算操作收到了更多的限制,即只能从一端放入数据,也只能从一端读取数据。存取数据的一端称作栈顶top,另一端的栈底bottom不允许做任何存取的操作。取出栈最上面的元素(栈顶top)这个操作叫做pop,存入元素的操作叫push,当堆栈为空时叫做空栈。
????举个通俗的栗子:洗完碗,我们一个叠一个放好,自然是先放最下面一个碗,然后才能继续往上放碗,拿碗的时候也是先拿上面的碗,拿完了才能拿下面的碗。在这里插入图片描述
????栈的特征是后进先出。至于栈的具体实现,我们可以自己写。最简单的实现方式就是用一个数组,只在数组的尾部进行元素的push和pop即可。当然更常用的是调用C++的STL库,里面有封装好的stack数据类型,使用起来更加方便。

2.队列queue

????队列queue是另一种限定存取位置的线性表。它只允许在队列的一段存入数据push,只允许在队列的另一端取出数据pop。允许插入的一端叫做队尾,允许取出的一端叫做队头。
????举个通俗的栗子:一队人在食堂排队打饭,大家的素质都很高。每来一个人都自动站到队尾,队头的那个人先打饭,打完饭后离开队伍。这种先进先出的数据结构就叫做队列。

二.应用

1.stack数制转换

????一个数从10进制转换为2进制,方法为:将这个数不停的整除2,直到余数为0为止。所有的商运算结果倒序输出就是最终的答案。因为这个计算算过程是从低位到高位逐个进行的,但是输出过程是从高位到低位的。因此需要用栈来实现。

#include <stdio.h>
#include <stack>
using namespace std;
int main() {
	int x;
	printf("请输入一个十进制数:");
	scanf("%d", &x);
	int tmp = x;
	stack<int>n;
	while (tmp != 0) {
		n.push(tmp % 2);
		tmp /= 2;
	}
	printf("%d 的二进制为 ", x);
	while (!n.empty()) {
		printf("%d", n.top());
		n.pop();
	}
	printf("\n");
}

2.stack括号匹配

????一串算式,里面会有很多括号,我们需要面对的难题是:

  • 这个算式中的括号是否合法:(1+2))
  • 加上了括号,算式的优先级又该如何考虑

????这里我们先解决第一个问题,也就是括号匹配问题。
????自左向右开始扫描算式,只要遇到左括号‘(’就立刻让它进栈。如果遇到右括号‘)’,分两种情况考虑:如果堆栈是空的,那么直接报错后退出程序。如果堆栈不是空的,再看栈顶,若栈顶是左括号‘(’,就将左括号‘(’抛出,如果栈顶是右括号‘)’,就将当前读到的右括号压入栈中。
????具体的代码实现我们在下一部分一并给出。

3.表达式的计算和优先级的处理(中缀转后缀)

????在前面,我们已经知道了如何进行括号的匹配。但是,在进行表达式计算的时候,我们还需要考虑到各运算符的优先级的问题。

  • 加减<乘除<幂运算
  • 当符号优先级一样时,从左往右先出现的运算符优先运算。(幂运算很特殊,要注意不遵守此条,可以考虑 a b c a^{b^c} abc,就是b和c先结合)

????基于上述考虑,我们已经有了如下思路:
????开两个堆栈,figures存放字母,opt存放运算符。读到数字就往figures里push,读到运算符就往opt里push。如果当前读到的运算符的优先级比opt的top低的话,那opt就出栈,并从figures中出栈2个字母参与运算,直到opt的栈顶优先级比当前读到的运算符低或者空栈,再将当前的运算符push。
????注意:左括号在堆栈外优先级最高,一旦进入栈中优先级变最低。

#include <stdio.h>
#include <string.h>
#include <stack>
using namespace std;
char operation[100000];
stack<char>x;
int compare_opt(char a, char b) {//如果负数,a优先级比b低,如果正数,a优先级比b高
	int x, y;
	if (a == '+' || a == '-') x = 1;
	else if (a == '^')x = 3;
	else if (a == '(')x = 0;
	else x = 2;
	if (b == '*' || b == '/')y = 2;
	else if (b == '^')y = 10;
	else if (b == '(')y = 0;
	else y = 1;

	return x - y;
}
int main() {
	int N;
	scanf("%d", &N);
	getchar();
	while (N) {
		gets(operation);
		int len = strlen(operation);
		for (int i = 0; i < len - 1; i++) {
			if ((operation[i] <= 'z' && operation[i] >= 'a') || (operation[i] <= 'Z' && operation[i] >= 'A')) {
				//当前读到的是字母
				printf("%c", operation[i]);
			}
			else {
				//当前读到的是运算符
				//首先判断是不是特殊运算符
				if (operation[i] == '(') {
					x.push(operation[i]);
				}
				else if (operation[i] == ')') {
					//遇到了右括号
					while (x.top() != '(') {
						printf("%c", x.top());
						x.pop();
					}
					x.pop();
				}
				else {
					//常规运算符
					if (x.empty()) {
						x.push(operation[i]);
					}
					else {
						while (!x.empty() && compare_opt(x.top(), operation[i]) >= 0) {
							if (operation[i] == '^' && compare_opt(x.top(), operation[i]) == 0)break;//注意幂运算的特殊
							printf("%c", x.top());
							x.pop();
						}
						x.push(operation[i]);
					}

				}

			}
		}
		while (!x.empty()) {
			printf("%c", x.top());
			x.pop();
		}
		printf("\n");
		N--;
	}
}

4.queue输出杨辉三角行

????在计算机中,队列常常用于解决需要逐行处理的问题。杨辉三角行就是一个典型的分层处理的例子。杨辉三角行的每一行的数字正好对应二项式 ( a + b ) i (a+b)^i (a+b)i展开各项的系数。
图片源自网络
????杨辉三角行的一个性质为:它的第i行的各个数字对应第i-1相应的两个数字的相加。我们可以采用一个队列,逐层处理这个分层结构。具体代码如下

#include <stdio.h>
#include <queue>
using namespace std;
int main() {
	int n;
	int x = 0, y;
	queue<int>que;
	scanf("%d", &n);
	//第一行的两个系数预先压入队列
	que.push(1);que.push(1);
	for (int i = 1; i < n; i++) {
		printf("\n");
		que.push(0);
		for (int j = 1; j <= i + 2; j++) {
			y = que.front(); que.pop();
			que.push(x + y);
			x = y;
			if (j != i + 2)printf(" %d", x);
		}
	}
}

5.利用堆栈把递归过程改成非递归过程

????先来看一个递归的经典,汉诺塔问题。

#include <stdio.h>
void Hanoi(int n, char A, char B, char C) {
	//有n个盘子,从A借助B挪动到C
	if (n == 1)
		printf("Move disk from %c to %c.\n", A, C);
	else {
		Hanoi(n - 1, A, C, B);//把A上的n-1个盘子通过C移动到B
		printf("Move disk from %c to %c.\n", A, C);
		Hanoi(n - 1, B, A, C);//把刚刚挪动的B通过A堆到C上
	}
}
int main() {
	int n;
	scanf("%d", &n);
	Hanoi(n, 'A', 'B', 'C');
}

????这里采用了分治法的思路。将n个盘子的移动分解为一个盘子(把n-1个盘子打包看作1个)和另一个盘子之间如何移动,将求解规模为n的问题分解成了两个规模为n-1的问题。按照这种自顶向下,逐层分解的原则,从而设计出来递归算法。
????但是,稍加分析我们发现,这个算法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),和递归深度的平方成正比。同时,由于递归调用时需要调用递归工作栈存放每一轮递归的局部变量的,因此空间复杂度为 O ( n ) O(n) O(n)
????这很不妙。因此,我们希望利用栈把它改成非递归的,希望能对其时空复杂度进行优化。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:31:37  更:2021-10-09 16:32:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 10:48:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码