数据结构之栈

什么是栈

栈是一种运算受限的线性表,它限定只能在表的一端进行插入和删除操作。栈的结构特性是:后进先出LIFO ( Last In First Out)。栈又被称为后进先出表。

栈顶:允许插入和删除的一端称作栈顶

栈顶:不允许插入和删除的一端称作栈底

链式栈

栈基本操作

  • 创建栈:create_stack

  • 入栈: push_stack

  • 出栈: pop_stack

  • 获取栈顶元素:top_stack

  • 栈是否为空:empty_stack

  • 栈元素个数: size_stack

数组链表实现代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int DataType;
typedef struct Stack 
{
	DataType* memory;//数据
	int top;//顶点位置
	int maxSize;//最大存入量
}Stack;

Stack* create_stack() 
{
	Stack* stack = (Stack*)calloc(1, sizeof(Stack));
	assert(stack);
	stack->top = -1;
	return stack;
}
void push_stack(Stack* stack, DataType data) 
{
	assert(stack);
	//内存自动增长
	if (stack->top+1 == stack->maxSize) 
	{
		stack->maxSize += 10;
		DataType* temp = (DataType*)realloc(stack->memory, sizeof(DataType) * stack->maxSize);//重新分配内存并赋值为一
		assert(temp);
		stack->memory = temp;
	}
	stack->memory[++stack->top] = data;
}
int size_stack(Stack* stack)
{
	return stack->top + 1;
}
bool empty_stack(Stack* stack)
{
	assert(stack);
	return stack->top == -1;
}
#if 0
//个人喜欢写法
void pop_stack(Stack* stack) 
{
	assert(stack);
	if (empty_stack(stack)) 
	{
		printf("栈为空无法出栈!\n");
		return;
	}
	stack->top--;
}
DataType top_stack(Stack* stack) 
{
	assert(stack);
	return stack->memory[stack->top];
}
#endif

DataType pop_stack_(Stack* stack) 
{
	return stack->memory[stack->top--];
}

void pop_stack_s(Stack* stack,DataType* value)
{
	*value=stack->memory[stack->top--];
}

int main() 
{
	Stack* stack = create_stack();
	push_stack(stack,1);
	push_stack(stack,2);
	push_stack(stack,3);
	while (!empty_stack(stack)) 
	{
#if 0
		printf("%d\t", top_stack(stack));
		pop_stack(stack);

#endif
		//printf("%d\t",pop_stack_(stack));
		int value = 0;
		pop_stack_s(stack, &value);
		printf("%d\t", value);
	}
	printf("\n");
	return 0;
}
链式表实现代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int DataType;

typedef struct Node 
{
	DataType data;
	struct Node* next;//地址指向下一个链表元素(下一个要从栈出来的元素)
}Node;

Node* create_node(DataType data) 
{
	Node* newNode = (Node*)calloc(1, sizeof(Node));
	assert(newNode);
	newNode->data = data;
	return newNode;
}
typedef struct Stack 
{
	Node* top;
	int count;
}Stack;

Stack* create_stack() 
{
	Stack* stack = (Stack*)calloc(1, sizeof(Stack));
	assert(stack);
	return stack;
}
bool empty_stack(Stack* stack)//将元素个数设为空(清空)
{
	assert(stack);
	return stack->count == 0;
}
int size_stack(Stack* stack) //返回元素个数
{
	assert(stack);
	return stack->count;
}
DataType top_stack(Stack* stack) 
{
	assert(stack);
	assert(stack->top);
	return stack->top->data;
}

void push_stack(Stack* stack, DataType data) 
{
	assert(stack);
	Node* newNode = create_node(data);
	newNode->next = stack->top;
	stack->top = newNode;
	stack->count++;元素加一
}
void pop_stack(Stack* stack) 
{
	assert(stack);
	if (stack->top == NULL) 
	{
		printf("栈为空,无法出栈\n");
		return;			//exit(1);
	}
	Node* nextNode = stack->top->next;
	free(stack->top);
	stack->top = nextNode;
	stack->count--;
}
int main() 
{
	Stack* stack = create_stack();
	push_stack(stack, 1);
	push_stack(stack, 2);
	push_stack(stack, 3);
	while (!empty_stack(stack)) 
	{
		printf("%d\t", top_stack(stack));
		pop_stack(stack);
	}
	printf("\n");
	return 0;
}
栈的应用小实例
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//({})
bool match(const char* str) 
{
	//创建栈
	char stack[1024];
	int top = -1;
	
	int i = 0;
	while (str[i] != '\0') 
	{
		if (str[i] == '(') 
		{
			//入栈操作
			stack[++top] = str[i];
		}
		else if (str[i] == ')') 
		{
			//出栈
			if (top > -1) 
			{
				top--;
			}
			else
			{
				return false;
			}
		}
		i++;
	}
	if (top == -1) 
	{
		return true;
	}
	else 
	{
		return false;
	}
}
int main() 
{
	while (true) 
	{
		char str[1024] = "";
		gets_s(str, 1024);
		if (match(str) == true) 
		{
			printf("匹配!\n");
		}
		else 
		{
			printf("不匹配\n");
		}
	}
	return 0;
}

运行结果

实例2:表达式求值详解

中缀表达式

我们把平时所用的标准四则运算表达式,即“9+(3-1)×3+10÷2”叫做中缀表达式。因为所有的运算符号都在两数字的中间。

后缀表达式

    将中缀表达式转化为后缀表达式:栈内只存符号,遇到右边括号就要出栈,出到左括号,遇到乘 法要比优先级

后缀表达式也叫作逆波兰表达式,对于“9+(3-1)×3+10÷2”,如果要用后缀表示法应该是什么样子:“9 3 1-3*+10 2/+”,这样的表达式称为后缀表达式,叫后缀的原因在于所有的符号都是在要运算数字的后面出现。后缀表达式如何求解表达式的值?

  • 遍历后缀表达式,如果遇到数字则直接入栈,如果遇到操作符,则弹出栈顶的两个元素,进行计算后将结果入栈。

  • 最终,栈内剩余的元素就是整个表达式的计算结果。

 

照着原理可以写出如下代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <ctype.h>
typedef double DataType;

#if 0

enum ValueType {IsChar,isNumber,IsDouble};
typedef struct Data
{
	int type;       
	union 
	{
		char strValue;
		int  intVlaue;
		double doubleValue;
	};
}Data;

typedef struct Stack_
{
	Data* memory;
	int top;
	int maxSize;
}Stack_;

#endif 

typedef struct Stack
{
	DataType* memory;
	int top;
	int maxSize;
}Stack;
Stack* create_stack()
{
	Stack* stack = (Stack*)calloc(1, sizeof(Stack));
	assert(stack);
	stack->top = -1;
	return stack;
}
void push_stack(Stack* stack, DataType data)
{
	assert(stack);
	//内存自动增长
	if (stack->top + 1 == stack->maxSize)
	{
		stack->maxSize += 10;
		DataType* temp = (DataType*)realloc(stack->memory, sizeof(DataType) * stack->maxSize);
		assert(temp);
		stack->memory = temp;
	}
	stack->memory[++stack->top] = data;
}
int size_stack(Stack* stack)
{
	return stack->top + 1;
}
bool empty_stack(Stack* stack)
{
	assert(stack);
	return stack->top == -1;
}
void pop_stack(Stack* stack)
{
	assert(stack);
	if (empty_stack(stack))
	{
		printf("栈为空无法出栈!\n");
		return;
	}
	stack->top--;
}
DataType top_stack(Stack* stack)
{
	assert(stack);
	return stack->memory[stack->top];
}
//辅助函数
//判定是否是运算符
bool is_operator(char key) 
{
	return key == '+' || key == '-' || key == '*' || key == '/';
}
//优先级判定
int pri_operator(char key) 
{
	switch (key) 
	{
	case '+':
	case '-':
		return 1;
	case '*':
	case '/':
		return 2;
	default:
		return 0;
	}
}
//中缀转后缀
void  midFix_top_lastFix(char* midFix, char* lastFix) 
{
	Stack* stack = create_stack();
	char* p = midFix;
	char* q = lastFix;
	while (*p != '\0') 
	{
		//3.3+43	
		if (isdigit(*p)) //#include <ctype.h>
		{	//如果是数字
			while (isdigit(*p) || *p == '.') 
			{
				*q = *p;
				q++;
				p++;
			}
			//数字与数字要有间隔
			*q = ' ';
			q++;
		}
		else if (*p == '+' || *p == '-' || *p == '*' || *p == '/') 
		{
			//如果运算符
			int pri = pri_operator(*p);			//当前字符的优先级
			//低于优先一直出栈,把栈中的的运算符拿出来放到后缀表达式中
			while (!empty_stack(stack)&&is_operator(top_stack(stack))&&pri_operator(top_stack(stack))>=pri) 
			{
				char op = top_stack(stack);
				pop_stack(stack);
				//出栈的运算符要放到后缀表达式中
				*q = op;
				q++;
				*q = ' ';
				q++;
			}
			//高于 入字符栈
			push_stack(stack, *p);
			p++;
		}
		else if (*p == '(') 
		{
			push_stack(stack, *p);
			p++;
		}
		else if (*p == ')') 
		{
			//遇到右边括号出栈到左边括号为止
			while (!empty_stack(stack) && top_stack(stack) != '(') 
			{
				char op = top_stack(stack);
				pop_stack(stack);
				*q = op;
				q++;
				*q = ' ';
				q++;
			}
			if (!empty_stack(stack) && top_stack(stack) == '(') 
			{
				pop_stack(stack);//将括号删掉
			}
			else 
			{
				printf("error\n");
			}
			p++;
		}
		else 
		{
			//其他的直接跳过
			p++;
		}
	}
	//栈中剩余的运算符 直接连接到后缀表达式中
	while (!empty_stack(stack)) 
	{
		char op = top_stack(stack);
		pop_stack(stack);
		*q = op;
		q++;
		*q = ' ';
		q++;
	}
	//字符串结束标记
	*(q - 1) = '\0';
}

//辅助函数
double operator_num(double left, double right, char op) 
{
	switch (op) 
	{
	case '+':
		return left + right;
		break;
	case '-':
		return left - right;
		break;
	case '*':
		return left * right;
		break;
	case '/':
		return left / right;
		break;
	default:
		return 0.0;
		break;
	}
}

double calc_result(char* lastFix) 
{
	Stack* stack = create_stack();
	char* p = lastFix;
	while (*p != '\0') 
	{
		if (isdigit(*p)) 
		{
			//23.456
			double num = *p - '0';             //2
			p++;
			while (isdigit(*p) || *p == '.')   //234
			{
				if (*p == '.') 
				{
					p++;
					double dec = 0.1;
					while (isdigit(*p)) 
					{
						num += (*p - '0') * dec;
						p++;
						dec /= 10;
					}
					break;
				}
				else 
				{
					num = num * 10 + (*p - '0');  //2*10+3-'0'=23  23*10+4-'0'=234
					p++;
				}
			}
			//记得入栈
			push_stack(stack, num);
		}
		else if (*p == '+' || *p == '-' || *p == '*' || *p == '/') 
		{
			double right = top_stack(stack);
			pop_stack(stack);
			double left = top_stack(stack);
			pop_stack(stack);
			double result = operator_num(left, right, *p);
			push_stack(stack, result);
			p++;
		}
		else 
		{
			p++;
		}
	}
	double value = top_stack(stack);
	pop_stack(stack);
	return value;
}
int main()
{
	char  midFix[100] = "";
	char lastFix[100] = "";
	while (true) 
	{
		printf("input midFix:");
		gets_s(midFix, 100);
		midFix_top_lastFix(midFix, lastFix);
		printf("lastFix:%s\n", lastFix);//测试后缀表达式
		printf("%s=%lf\n", midFix, calc_result(lastFix));//计算数值
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值