顺序栈学习笔记

本文详细介绍了顺序栈的基本操作,包括初始化、入栈、出栈、清空、销毁、获取容量和判断栈是否为空,并探讨了如何使用栈实现中缀表达式转后缀表达式及后缀表达式的计算,特别强调了内存管理和数据精度问题。
摘要由CSDN通过智能技术生成


一. 顺序栈的简单操作

以下为一些基础的操作函数。

1.1 顺序栈的定义

(栈的容量大小可变)

#include<bits/stdc++.h>
using namespace std; 

#define MAXSIZE 10

typedef int Elemtype;
typedef struct{
	Elemtype *base;		//栈底 
	Elemtype *top;		//栈顶 
	int stack;			//最大空间 
}SqStack;

1.2 初始化栈

//初始化栈 
void init(SqStack *s){
	s->base=(int *)malloc(MAXSIZE*sizeof(int));
	s->top=s->base;		//最初栈顶和栈底重合 
	s->stack=MAXSIZE;	//初始最大容量
}

1.3 入栈和出栈

(出栈时输出栈顶元素)

//入栈 
void push(SqStack *s,Elemtype e){
	if(s->top-s->base>s->stack){
		s->base=(int*)realloc(s->base,(s->stack++)*sizeof(int));  //重新申请空间(长度+1)
		s->top=s->base+s->stack;	//设置栈顶
		s->stack++;                 //最大容量+1 
	}
	*(s->top)=e;
	s->top++;
}

//出栈并输出栈顶元素
int pop(SqStack *s){
	if(s->top==s->base)//栈为空栈 
		return 0;
	printf("%d",*(--s->top));
}

1.4 清空与销毁栈

//清空栈
void clear(SqStack *s){
	s->top=s->base;
}

//销毁栈
void Destroys(SqStack *s){
	int i;
	for(i=0;i<s->stack;i++){
		free(s->base);	//释放栈底 
		s->base++;		//栈底往栈顶方向移动
	}
	s->base=s->top=NULL;
	s->stack=0;
}

1.5 获取栈的容量

//获取栈的当前容量 
int Stacklen(SqStack *s){
	return (s->top-s->base);
}

1.6 判断栈是否为空

//判断栈是否为空 
int StackEmpty(SqStack s){
	if(s.base==s.top){
		return true;
	}
	return false;
} 

1.7 主程序

(这里写出了创建栈的过程)

int main(){
	SqStack s;
	//初始化 
	init(&s);
	int n,m;
	printf("输入元素个数:");
	cin>>n;
	printf("输入元素",n);
	for(int i=0;i<n;i++){
		cin>>m;
		//入栈 
		push(&s,m);
	}
	return 0;
}


二. 中缀表达式转后缀表达式

利用栈进行运算符号的储存,atof()函数将输入的字符串转化为数字输出。

(注:这里可以选择直接输出字符。这里转换成数字是因为当初想到用链栈来完成运算符号和数字的储存以便在同一个程序中完成后缀表达式的计算)。

2.1 定义栈

#include<bits/stdc++.h>
using namespace std; 

#define MAXSIZE 100
 
//后缀表达式符号链表 
typedef char Elemtype;
typedef struct{
	Elemtype *base;		//栈底 
	Elemtype *top;		//栈顶 
	int stack;			//最大空间 
}SqStack;

2.2 栈的相关操作函数

//初始化栈(char) 
void initc(SqStack *s){
	s->base=(char *)malloc(MAXSIZE*sizeof(char));
	s->top=s->base;		//最初栈顶和栈底重合 
	s->stack=MAXSIZE;	//初始最大容量
}

//入栈(char) 
void pushc(SqStack *s,char c){
	if(s->top-s->base>s->stack){
		s->base=(char *)realloc(s->base,(s->stack++)*sizeof(char));  //重新申请空间(长度+1)
		s->top=s->base+s->stack;	//设置栈顶
		s->stack++;                 //最大容量+1 
	}
	*s->top++=c;
}

//出栈(char)
int popc(SqStack *s,char *c){
	if(s->top==s->base)//栈为空栈 
		return 0;
	*c=*(--s->top);
	return 1; 
}

//获取栈的容量 
int Stacklen(SqStack *s){
	return (s->top-s->base);
}

//判断栈是否为空 
int StackEmpty(SqStack *s){
	if(s->base==s->top){
		return true;
	}
	return false;
} 

2.3 转换函数*

该转换函数可以读取小数。

(需要注意,tempstr字符串数组应该使用malloc分配内存,而不是采用tempstr[10]的形式。使用后者在遍历时无法清空内存,可能会导致实际字符串长度大于数字位数的情况。)

//中缀表达式转后缀表达式 
void Change(SqStack *s,char *str){ 
	//遍历索引 
	int i=0;
	//数字和符号索引 
	int index=0; 
	//遍历字符串 
	while(str[i]){
		//临时储存数字的字符串 
		char *tempstr=(char*)malloc(sizeof(char)*10);
		//避免重复输出数字 
		int flag=0;
		int j=0; 
		//判断是否为数字或小数点 
		while(isdigit(str[i])||str[i]=='.'){
			tempstr[j++]=str[i++];
			flag=1;
		}
		//输出数字 
		if(flag==1){
			printf("%.1lf ",atof(tempstr));
			flag=0;
		}
		else{		
			//临时变量储存符号 
			char c;
			//如果为加减运算符
			if(str[i]=='+'||str[i]=='-'){ 
				//栈为空,直接压入 
				if(Stacklen(s)==0){
					pushc(s,str[i]);
				}
				//否则将栈中其他符号压出直至碰到左括号 
				else{
					do{
						popc(s,&c);
						//左括号重新压入 
						if(c=='('){
							pushc(s,c);
						}
						//输出符号 
						else{
							printf("%c ",c);
						}
					}while(Stacklen(s)&&c!='(');
					//压入加减符号 
					pushc(s,str[i]);
				}
			}
			//如果是右括号,不压入,直接压出直至碰到左括号 
			else if(str[i]==')'){
				popc(s,&c);
				while(c!='('){
					printf("%c ",c);
					popc(s,&c);
				}
			}
			//乘、除、左括号直接压栈
			else if(str[i]=='*'||str[i]=='/'||str[i]=='('){
				pushc(s,str[i]);
			}
			//消除空格的影响 
			else if(str[i]=='\0'){
				i++;
				continue;
			}
			//格式错误 
			else{
				printf("\n输入格式错误!\n");
				return;
			}
			i++;
		}
	}
	char c;
	//栈中剩余元素出栈 
	while(Stacklen(s)!=0){
		popc(s,&c); 
		printf("%c ",c);
	}
	
}

2.4 主函数

int main(){
	SqStack s;
	//初始化 
	initc(&s);
	//中缀字符串 
	char str[100]; 
	cin>>str;
	//转换 
	Change(&s,str);
	
	return 0;
}


三. 后缀表达式的计算

利用栈进行数字的储存,可计算小数,atof()函数将输入的字符串转化为数字存入栈中。

需要注意的是:

  1. 出栈(pop)时函数要设置为double型,否则会导致数字精度发生改变。
  2. 最后一次出栈时直接调用pop()函数即可。(开始做的时候忘记出栈函数是直接返回栈顶元素的,导致使用printf函数输出pop()时结果一直是0.0···)。

3.1 定义栈

#include<bits/stdc++.h>
using namespace std;

#define MAXSIZE 100

//后缀表达式符号栈 
typedef double Elemtype;
typedef struct{
	Elemtype *base;		//栈底 
	Elemtype *top;		//栈顶 
	int stack;			//最大空间 
}SqStack;

3.2 栈的相关操作函数

//初始化栈(double) 
void init(SqStack *s){
	s->base=(double *)malloc(MAXSIZE*sizeof(double));
	s->top=s->base;		//最初栈顶和栈底重合 
	s->stack=MAXSIZE;	//初始最大容量
}

//入栈(double) 
void push(SqStack *s,double c){
	if(s->top-s->base>s->stack){
		s->base=(double *)realloc(s->base,(s->stack++)*sizeof(double));  //重新申请空间(长度+1)
		s->top=s->base+s->stack;	//设置栈顶
		s->stack++;                 //最大容量+1 
	}
	*s->top++=c;
}

//出栈并输出栈顶元素 
double pop(SqStack *s){
	if(s->top==s->base)//栈为空栈 
		return 0;
	s->top--;
	return *(s->top);
}

//获取栈的容量 
int Stacklen(SqStack *s){
	return (s->top-s->base);
}

3.3 主函数和后缀表达式的计算*

int main(){
	SqStack s;
	//初始化 
	init(&s);
	string str;
	//输入带空格的字符串 
    getline(cin,str);
    //遍历字符串 
    int i=0;
	while(str[i]){
		//临时储存数字的字符串
		char *tempstr=(char*)malloc(sizeof(char)*10);
		//避免重复输出数字 
		int flag=0;
		int j=0; 
		//判断是否为数字或小数点 
		while(isdigit(str[i])||str[i]=='.'){
			tempstr[j++]=str[i++];
			flag=1;
		}
		//输出数字 
		if(flag==1){
			//printf("%.1lf ",atof(tempstr));
			push(&s,atof(tempstr));
			flag=0;
		}
		//如果是符号 
		else if(str[i]=='+'||str[i]=='-'||
			str[i]=='*'||str[i]=='/'){
			//出栈并且得到栈顶元素 
			double num1,num2,res;
			num1=pop(&s);
			num2=pop(&s);
			switch(str[i]){
				case '+':res=num2+num1;push(&s,res);break;
				case '-':res=num2-num1;push(&s,res);break;
				case '*':res=num2*num1;push(&s,res);break;
				case '/':res=num2/num1;push(&s,res);break;
			}
		}
		i++;
	}
	//结果 
	cout<<pop(&s);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值