C/C++语言数据结构快速入门(代码解析+内容解析)栈的应用

Posted 蓝盒子bluebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++语言数据结构快速入门(代码解析+内容解析)栈的应用相关的知识,希望对你有一定的参考价值。

一、括号匹配


1、算法演示

#include<stdio.h>
#define MaxSize 10		//定义栈中元素的最大值 
typedef struct {
	char data[MaxSize];//静态数组当中存放栈中元素 
	int top;			//栈顶指针 
}SqStack;

bool bracketCheck(char str[],int length){
	SqStack S;
	InitStack(S);
	for(int i = 0; i < length;i++){
		if(str[i] == '(' || str[i] == '[' || str[i] == '{' ){
			Push(S,str[i]);
		}else{
			if(StackEmpty(S))
				return false;
			char topElem;
			Pop(S,topElem);//栈顶元素出栈
			if(str[i] == ')' && topElem != '(')
				return false;
			if(str[i] == ']' && topElem != '[')
				return false;
			if(str[i] == '}' && topElem != '{')
				return false;
		}
	}
	return StackEmpty(S);  //检索完全括号后,栈空的说明匹配成功 
} 
//初始化栈
void InitStack(SqStack &S)

//判断栈是否为空
bool StackEmpty(SqStack S)

//新元素入栈
bool Push(SqStack &S,char x)

//栈顶元素出栈,用x返回
bool Pop(SqStack &S,char x) 

二、表达式求值

1、大家熟悉的算数表达式

波兰数学家的灵感

2、中缀、后缀、前缀表达式

3、中缀表达式转后缀表达式

中缀转后缀的手算方法:
①确定中缀表达式中各个运算符的运算顺序
②选择下一个运算符,按照「左操作数右操作数运算符」的方式组合成-一个新的操作数
③如果还有运算符没被处理,就继续②


私房菜:
“左优先”原则,不要FreeStyle,保证手算和机算结果相同
左优先”原则:只要左边的运算符能先计算,就优先算左边的(可保证运算顺序唯)

4、后缀表达式的计算


后缀表达式的手算方法:

从左往右扫描,每遇到-一个运算符,就让运算符前面最近的两个操作数执行对应运算,合体为一个操作数

注意:两个操作数的左右顺序

(1)代码实现


5、中缀表达式转前缀表达式

中缀转前缀的手算方法:
①确定中缀表达式中各个运算符的运算顺序
②选择下一个运算符,按照「运算符左操作数右操作数」的方式组合成一一个新的操作数
③如果还有运算符没被处理,就继续②
“右优先”原则:只要右边的运算符能先计算,就优先算右边的


6、知识点总结

7、中缀表达式转后缀表达式(计算机实现)

初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。
从左到右处理各个元素,直到末尾。可能遇到三种情况:

①遇到操作数。直接加入后缀表达式。

②遇到界限符。遇到“(”直接入栈;遇到“)”则依次弹出栈内运算符并加入后缀表达式,直到弹出“(”为止。注意:“(”不加入后缀表达式。

③遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到“(”或栈空则停止。之后再把当前运算符入栈。(*/优先级高于±)

(1)普通的表达式

按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。

扫描一个操作数则直接输出

扫描到符号因为现在栈为空

扫描到B是操作数直接输出

当扫描搭配-号的时候:遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到“(”或栈空则停止。之后再把当前运算符入栈。(*/优先级高于±)

弹出+号

然后将-号放入到栈当中

扫描到C是一个操作数,直接输出

扫描到*的时候,栈当中的减号不能弹出,将*放入到栈当中

扫描到D,D是操作数直接输出

当移动到/的时候,将*弹出栈

然后将/入栈

继续往后是一个操作数可以往后直接输出

移动到+号时将优先级更高的/号弹出栈

移动到+号时将优先级相等 的的-号弹出栈

+号入栈

最后将剩余的内容全部弹出

(2)带有界限符的表达式




遇到左括号直接入栈


移动到-号的时候

继续往后操作数直接输出

当遇到括号的时候先弹出-号,然后弹出括号

移动到-号的时候将运算符优先级高于-号和运算符等于-号的元素依次弹出


/优先级要比-号更高直接将/号入栈


然后将栈当中的数依次弹出加到后缀表达式当中

8、中缀表达式的计算(用栈实现)(中缀转后缀+后缀表达式求值【两个算法的结合】)

(1)实现方式一:用栈实现中缀表达式的计算:

初始化两个栈,操作数栈和运算符栈,

若扫描到操作数,压入操作数栈

若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈
(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈)

栈实现后缀表达式的求值














用于存放当前暂时还不能确定运算次序的操作数

(2)实现方式二:用栈实现中缀表达式的计算:

初始化两个栈,操作数栈和运算符栈若扫描到操作数,压入操作数栈。

若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈。

(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈)












9、知识回顾与重要考点

用栈实现中缀表达式转后缀表达式:

初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。

从左到右处理各个元素,直到末尾。可能遇到三种情况:

(1)遇到操作数。直接加入后缀表达式。
(2)遇到界限符。遇到“(”直接入栈;遇到“)”则依次弹出栈内运算符并加入后缀表达式,直到弹出“(”为止。注意:“(”不加入后缀表达式。
(3)遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到“(”或栈空则停止。之后再把当前运算符入栈。

按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。用栈实现后缀表达式的计算:
(1)从左往右扫描下一个元素,直到处理完所有元素
(2)若扫描到操作数则压入栈,并回到(1);否则执行(3)
(3)若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到(1)

用栈实现中缀表达式的计算:

初始化两个栈,操作数栈和运算符栈若扫描到操作数,压入操作数栈

若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈

(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈)

三、递归

1、函数调用背后的过程


函数调用的特点:最后被调用的函数最先执行结束((LIFO)

函数调用时,需要用一个栈存储
(1)调用返回地址
(2)实参
(3)局部变量

2、栈在递归当中的应用

适合用“递归”算法解决:可以把原始问题转换为属性相同,但是规模较小的问题。

Eg1:计算正整数的阶乘n!

Eg2:求斐波那契数列


递归表达式(递归体)
边界条件(递归出口)

#include<stdio.h>
//计算正整数 n!
int factorial(int n){
	if(n == 0 || n == 1)
		return 1;
	else
		return n*factorial(n-1);
} 
int main(){
	//...其他代码
	int x = factorial(10);
	printf("奥利给x:%d",x); 
}


递归调用时,函数调用栈可称为“递归工作栈”

每进入一层递归,就将递归调用所需信息压入栈顶

每退出一层递归,就从栈顶弹出相应信息

Eg3:求斐波那契数列
#include<stdio.h>
//计算正整数 n!
int Fib(int n){
	if(n==0)
		return 0;
	else if(n==1)
		return 1;
	else
		return Fib(n-1) + Fib(n-2);
}
int main(){
	//..其他代码
	int x = Fib(4);
	printf("奥利给!x=%d",x); 
	
} 


3、函数调用栈



函数调用的特点:最后被调用的函数最先执行结束(LIFO)

函数调用时,需要用一个函数“函数调用栈”存储
(1)调用返回地址
(2)实参
(3)局部变量

递归调用的时候,函数调用栈可称为“递归工作栈”每进入一层递归,就将递归调用所需要的信息压入栈顶每退出一层递归,就从栈顶弹出相应信息

缺点:效率低,太多层递归可能会导致栈溢出;可能包含很多重复的计算

可以自定义栈将递归算法改造成非递归算法

以上是关于C/C++语言数据结构快速入门(代码解析+内容解析)栈的应用的主要内容,如果未能解决你的问题,请参考以下文章

C/C++语言数据结构快速入门(代码解析+内容解析)栈的应用

C/C++语言数据结构快速入门(代码解析+内容解析)栈

C/C++语言数据结构快速入门(代码解析+内容解析)栈

C/C++语言数据结构快速入门(代码解析+内容解析)队列的应用

C/C++语言数据结构快速入门(代码解析+内容解析)特殊矩阵

C/C++语言数据结构快速入门(代码解析+内容解析)队列