单链表堆栈的应用

说明

1、基于Visual Studio 2022环境,用C++实现
2、堆栈是用单链表实现的,堆栈的函数有

//初始化堆栈,带有头结点,头结点指向栈顶
void InitStack(LiStack& L);
//入栈,即头插法插入元素
void push(LiStack& L, ElemType i);
//判断栈是否为空
bool IsEmpty(LiStack L);
//出栈,即删除头结点的后一个结点
bool pop(LiStack& L);
//读栈顶元素,通过x返回值
bool GetTop(LiStack L, ElemType& x);
//销毁整个栈
void DestroyStack(LiStack& L);

3、主要是对堆栈的一些常见应用的实现
4、本人在学习数据结构后,依据算法实现的代码

具体有以下四个应用的实现

1、括号匹配算法

//括号匹配算法,基于堆栈
bool BracketMatching(char str[]) {
	LiStack S;
	InitStack(S);
	char x;
	int length = strlen(str);
	int i = 0;
	for (i = 0; i < length; i++) {
		if (str[i] == '(')
			push(S, str[i]);
		else if (str[i] == ')') {
			if (IsEmpty(S))
				return false;//此时有右括号,但堆栈为空,匹配失败
			GetTop(S, x);
			if (x == '(')
				pop(S);
			else
				return false;//左右括号不匹配
		}
		else
			return false;//传入的字符串中除了左右括号还有其他值
	}
	if (!IsEmpty(S))
		return false;//匹配完一轮后,堆栈中仍有左括号,匹配失败
	return true;
}

2、堆栈实现中缀表达式转后缀表达式

//栈实现中缀表达式转后缀表达式
bool InfixToExpression(char str[],char result[20]) {
	LiStack S;
	InitStack(S);
	char x = '\0';
	int length = strlen(str);
	char temp[20]="";
	int temp_len = 0;
	int i = 0;
	for(i=0;i<length;i++){
		if (str[i] == '(') {//左括号直接入栈
			push(S, str[i]);
		}
		else if (str[i] == '+') {//为 + 号,弹出 * / + - 运算符
			GetTop(S, x);//如果栈空,x则无值,不会进入while
			while (x == '*' || x == '/' || x == '-' || x == '+') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '-') {//为 - 号,弹出 * / + - 运算符
			GetTop(S, x);
			while (x == '*' || x == '/' || x == '+' || x == '-') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '*') {//为 * 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '/') {//为 / 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == ')') {//右括号,直接弹出栈中除 ( 的所有的运算符
			GetTop(S, x);
			while (!IsEmpty(S)) {
				if (x == '(') {
					pop(S);
					break;
				}
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
		}
		else if ((str[i] >= 48 && str[i] <= 57)|| (str[i] >= 65 && str[i] <= 90) ) {//为操作数,则直接加在表达式后
			temp[temp_len++] = str[i];
		}
		else {
			return false;//字符串中含有非法字符
		}
	}
	while (!IsEmpty(S)) {//最后弹出栈中所有的操作符
		GetTop(S, x);
		temp[temp_len++] = x;
		pop(S);
	}
	strcpy(result, temp);
	return true;
}

3、堆栈实现后缀表达式的计算

//后缀表达式的计算
void EvaluateSuffixExpression(char str[], int& result) {
	LiStack S;
	InitStack(S);
	int length = strlen(str);
	int temp = 0;//暂存结果
	char x1 = '\0';
	char x2 = '\0';
	int i = 0;
	for (i = 0; i < length; i++) {
		if (str[i] >= 48 && str[i] <= 57) {//为操作数,入栈
			push(S, str[i]-48);
		}
		else if (str[i] == '+') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 + x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
		else if (str[i] == '-') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 - x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
		else if (str[i] == '*') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 * x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
		else if (str[i] == '/') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 / x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
	}
	GetTop(S, x1);
	result = x1;
}

4、堆栈直接计算中缀表达式

//辅助函数,根据传入的堆栈和 运算符计算结果
int Calculation(LiStack& S, char x) {
	char x1 = '\0';
	char x2 = '\0';
	int temp = 0;

	if (x == '+') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 + x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	else if (x == '-') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 - x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	else if (x == '*') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 * x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	else if (x == '/') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 / x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	GetTop(S, x1);
	temp = x1;
	return temp;
}

//中缀表达式的计算
void CalculateInfixExpression(char str[], int& result) {
	LiStack S;//Symbol Stack
	LiStack O;//Operand Stack
	InitStack(S);
	InitStack(O);
	int temp = 0;//暂存结果
	int length = strlen(str);
	int i = 0;
	char x = '\0';
	for (i = 0; i < length; i++) {
		if (str[i] >= 48 && str[i] <= 57) {//为操作数,压入操作数栈
			push(O, str[i] - 48);
		}
		else if (str[i] == '(') {//左括号直接压入符号栈
			push(S, str[i]);
		}
		else if (str[i] == '+') {//为 + 号,弹出 * / + - 运算符,并进行运算
			GetTop(S, x);//如果栈空,x则无值,不会进入while
			while (x == '*' || x == '/' || x == '-' || x == '+') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '-') {//为 - 号,弹出 * / + - 运算符
			GetTop(S, x);
			while (x == '*' || x == '/' || x == '+' || x == '-') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '*') {//为 * 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '/') {//为 / 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == ')') {//右括号,直接弹出栈中除 ( 的所有的运算符
			GetTop(S, x);
			while (!IsEmpty(S)) {
				if (x == '(') {
					pop(S);
					break;
				}
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
		}
	}
	while (!IsEmpty(S)) {//弹出符号栈中剩余的运算符
		GetTop(S, x);
		Calculation(O, x);
		pop(S);
	}
	GetTop(O, x);
	result = x;
}

整体代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)

typedef char ElemType;

//定义单链表堆栈
typedef struct Linknode {
	ElemType date;
	struct Linknode* next;
}*LiStack, Linknode;

//初始化堆栈,带有头结点,头结点指向栈顶
void InitStack(LiStack& L) {
	LiStack Lnode = (LiStack)malloc(sizeof(Linknode));
	Lnode->date = 0;
	Lnode->next = NULL;
	L = Lnode;
}

//入栈,即头插法插入元素
void push(LiStack& L, ElemType i) {
	LiStack p = (LiStack)malloc(sizeof(Linknode));
	p->date = i;
	p->next = L->next;
	L->next = p;
}

//判断栈是否为空
bool IsEmpty(LiStack L) {
	if (L->next == NULL)
		return true;
	return false;
}

//出栈,即删除头结点的后一个结点
bool pop(LiStack& L) {
	if (IsEmpty(L))
		return false;
	LiStack p = L->next;
	L->next = p->next;
	free(p);
}

//读栈顶元素,通过x返回值
bool GetTop(LiStack L, ElemType& x) {
	if (IsEmpty(L)) {
		x = '\0';//栈空,x无值
		return false;
	}
	x = L->next->date;
	return true;
}

//销毁整个栈
void DestroyStack(LiStack& L) {
	LiStack p = L;
	if (p->next == NULL) {
		free(p);
		return;
	}
	LiStack q = p->next;
	while (q != NULL) {
		free(p);
		p = q;
		q = p->next;
	}
	return;
}

//括号匹配算法,基于堆栈
bool BracketMatching(char str[]) {
	LiStack S;
	InitStack(S);
	char x;
	int length = strlen(str);
	int i = 0;
	for (i = 0; i < length; i++) {
		if (str[i] == '(')
			push(S, str[i]);
		else if (str[i] == ')') {
			if (IsEmpty(S))
				return false;//此时有右括号,但堆栈为空,匹配失败
			GetTop(S, x);
			if (x == '(')
				pop(S);
			else
				return false;//左右括号不匹配
		}
		else
			return false;//传入的字符串中除了左右括号还有其他值
	}
	if (!IsEmpty(S))
		return false;//匹配完一轮后,堆栈中仍有左括号,匹配失败
	return true;
}

//栈实现中缀表达式转后缀表达式
bool InfixToExpression(char str[],char result[20]) {
	LiStack S;
	InitStack(S);
	char x = '\0';
	int length = strlen(str);
	char temp[20]="";
	int temp_len = 0;
	int i = 0;
	for(i=0;i<length;i++){
		if (str[i] == '(') {//左括号直接入栈
			push(S, str[i]);
		}
		else if (str[i] == '+') {//为 + 号,弹出 * / + - 运算符
			GetTop(S, x);//如果栈空,x则无值,不会进入while
			while (x == '*' || x == '/' || x == '-' || x == '+') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '-') {//为 - 号,弹出 * / + - 运算符
			GetTop(S, x);
			while (x == '*' || x == '/' || x == '+' || x == '-') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '*') {//为 * 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '/') {//为 / 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == ')') {//右括号,直接弹出栈中除 ( 的所有的运算符
			GetTop(S, x);
			while (!IsEmpty(S)) {
				if (x == '(') {
					pop(S);
					break;
				}
				temp[temp_len++] = x;
				pop(S);
				GetTop(S, x);
			}
		}
		else if ((str[i] >= 48 && str[i] <= 57)|| (str[i] >= 65 && str[i] <= 90) ) {//为操作数,则直接加在表达式后
			temp[temp_len++] = str[i];
		}
		else {
			return false;//字符串中含有非法字符
		}
	}
	while (!IsEmpty(S)) {//最后弹出栈中所有的操作符
		GetTop(S, x);
		temp[temp_len++] = x;
		pop(S);
	}
	strcpy(result, temp);
	return true;
}

//后缀表达式的计算
void EvaluateSuffixExpression(char str[], int& result) {
	LiStack S;
	InitStack(S);
	int length = strlen(str);
	int temp = 0;//暂存结果
	char x1 = '\0';
	char x2 = '\0';
	int i = 0;
	for (i = 0; i < length; i++) {
		if (str[i] >= 48 && str[i] <= 57) {//为操作数,入栈
			push(S, str[i]-48);
		}
		else if (str[i] == '+') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 + x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
		else if (str[i] == '-') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 - x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
		else if (str[i] == '*') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 * x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
		else if (str[i] == '/') {//为操作符,弹出栈顶两个元素进行运算
			GetTop(S, x1);
			pop(S);
			GetTop(S, x2);
			pop(S);
			temp = x2 / x1;
			push(S, temp);//int 转为 char,并压入堆栈
		}
	}
	GetTop(S, x1);
	result = x1;
}

//辅助函数,根据传入的堆栈和 运算符计算结果
int Calculation(LiStack& S, char x) {
	char x1 = '\0';
	char x2 = '\0';
	int temp = 0;

	if (x == '+') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 + x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	else if (x == '-') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 - x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	else if (x == '*') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 * x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	else if (x == '/') {//为操作符,弹出栈顶两个元素进行运算
		GetTop(S, x1);
		pop(S);
		GetTop(S, x2);
		pop(S);
		temp = x2 / x1;
		push(S, temp);//int 转为 char,并压入堆栈
	}
	GetTop(S, x1);
	temp = x1;
	return temp;
}

//中缀表达式的计算
void CalculateInfixExpression(char str[], int& result) {
	LiStack S;//Symbol Stack
	LiStack O;//Operand Stack
	InitStack(S);
	InitStack(O);
	int temp = 0;//暂存结果
	int length = strlen(str);
	int i = 0;
	char x = '\0';
	for (i = 0; i < length; i++) {
		if (str[i] >= 48 && str[i] <= 57) {//为操作数,压入操作数栈
			push(O, str[i] - 48);
		}
		else if (str[i] == '(') {//左括号直接压入符号栈
			push(S, str[i]);
		}
		else if (str[i] == '+') {//为 + 号,弹出 * / + - 运算符,并进行运算
			GetTop(S, x);//如果栈空,x则无值,不会进入while
			while (x == '*' || x == '/' || x == '-' || x == '+') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '-') {//为 - 号,弹出 * / + - 运算符
			GetTop(S, x);
			while (x == '*' || x == '/' || x == '+' || x == '-') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '*') {//为 * 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == '/') {//为 / 号,弹出 * / 运算符
			GetTop(S, x);
			while (x == '*' || x == '/') {
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
			push(S, str[i]);//弹出需要弹的后,将当前运算符入栈
		}
		else if (str[i] == ')') {//右括号,直接弹出栈中除 ( 的所有的运算符
			GetTop(S, x);
			while (!IsEmpty(S)) {
				if (x == '(') {
					pop(S);
					break;
				}
				Calculation(O, x);
				pop(S);
				GetTop(S, x);
			}
		}
	}
	while (!IsEmpty(S)) {//弹出符号栈中剩余的运算符
		GetTop(S, x);
		Calculation(O, x);
		pop(S);
	}
	GetTop(O, x);
	result = x;
}

int main() {
	/* 括号匹配
	char str[] = "(()()()(())";
	if (BracketMatching(str))
		printf("匹配成功!");
	else
		printf("匹配失败!");*/

	//中缀转后缀
	char str[] = "1+2*3-4/2";//转换结果:123*+42/- 计算结果:5
	char str1[] = "1*(8-2+3*2)/3*5";//转换结果:124+*3/5* 计算结果:20
	char str2[] = "A+B*(C-D)-E/F";//转换结果:ABCD-*+EF/-
	char str3[] = "(3+5*4/2+2*(1+1)*(2+2))";//转换结果:354*2/+211+*22+*+   计算结果:29
	char result[20] = "";
	if (InfixToExpression(str3, result)) {
		printf("转化的后缀表达式为:%s\n",result);
	}
	else
		printf("转化失败!");

	//直接计算中缀表达式
	int result2 = 0;
	CalculateInfixExpression(str3, result2);
	printf("%s 的 直接 计算结果为 :%d\n", str3, result2);

	//计算后缀表达式
	int result1 = 0;
	EvaluateSuffixExpression(result, result1);
	printf("%s 的 间接 结果为 :%d\n", result, result1);
	return 0;
}

注意:

1、代码为自己手敲代码;

2、有错误或更好的办法欢迎留言评论;

3、若有侵犯个人或团体的权益请及时联系我;

4、本文为原创,转载或引用请注明出处

本文作者:逍遥子

本文连接: https://www.cnblogs.com/femme/p/16418836.html

版权:本人个人所有

posted @ 2022-06-28 11:23  ~逍遥子~  阅读(71)  评论(0编辑  收藏  举报