最近学到数据结构栈的部分,为了加深记忆特意敲了栈基本算法的函数代码,并且运用栈来实现后缀式转化及计算的功能。
首先来简单的介绍一下栈的基本内容
定义:一种只能在一端进行插入(入栈)或删除(出栈)的线性表。
注意,栈是操作受限(只能在一端插删)的线性表,但受限的线性表也还是线性表。
特点:先进后出。
例如一条只有一人宽的死胡同,几个人进去,先进去一定是最后出来。
基本操作:
InitStack(s)
// 初始化栈,构造一个空栈 s 。
DestroyStack(s)
/ /销毁栈,释放栈 s 占用的空间。
StackEmpty(s)
/ /判断栈是否为空,空返回真,否则返回假。
Push(s,e)
/ /进栈,将元素 e 插入到栈 s 中作为栈顶元素。
Pop(s,e)
/ /出栈,从栈 s 中删除栈顶元素,并将其赋值给 e 。
GetTop(s,e)
/ /取栈顶元素,返回栈顶元素,将其值赋给 e 。
在c++的STL中有关于栈的部分,只要写入< stack >的头文件就可以像引用库函数一样引用栈的操作函数。但笔者现在对STL不甚理解,故在下面代码示例中写下各操作函数的源代码
代码示例:
头文件及函数声明部分
#include<iostream>
#include<cstdlib>
using namespace std;
#define N 200
typedef struct lei
{
char a;
double b;
struct lei *next;
}lei;
//------------------------------------字符型--------------------------------------------
void InitStack(lei *&s); //初始化 InitStack(s);
void DestroyStack(lei *&s); //销毁栈 DestroyStack(s);
bool StackEmpty(lei *s); //判断是否为空栈 StackEmpty(s);
void Push(lei *&s,char e); //进栈 Push(s,e);
bool Pop(lei *&s,char &e); //出栈 Pop(s,e);
bool GetTop(lei *s,char &e); //栈顶元素提取 GetTop(s,e);
void trans(char *exp,char postexp[]); //后缀式转换 trans(exp,postexp);
//-------------------------------------实型---------------------------------------------
void Push1(lei *&s,double e); //进栈 Push1(r,e);
bool Pop1(lei *&s,double &e); //出栈 Pop1(r,e);
bool GetTop1(lei *s,double &e); //栈顶元素提取 GetTop1(r,e);
double compvalue(char *postexp); //后缀式计算 compvalue(postexp);
主函数部分
int main()
{
char exp[]="2+1*2+(1+2/(4-2)+3)";
char postexp[N];
printf("中缀表达式:\t\t");
puts(exp);
trans(exp,postexp);
printf("后缀表达式:\t\t");
puts(postexp);
printf("计算结果保留两位小数: ");
printf("%.2lf\n",compvalue(postexp));
return 0;
}
功能函数部分
void trans(char *exp,char postexp[]) //后缀式转换 trans(exp,postexp);
{
int i=0;
char e;
lei *s;
InitStack(s); //栈初始化
while(*exp!='\0') //*exp 表示指针exp所指向的字符串的第一个字符
{
switch(*exp)
{
case '(': //判定为左括号
Push(s,'('); //左括号直接进栈
exp++; //扫描下一个字符
break;
case ')': //判定为右括号
Pop(s,e); //不为左括号是循环;目的是将该双括号内的的计算符全部存入postexp
while(e!='(')
{
postexp[i++]=e;
Pop(s,e); //先出栈(从栈中删除),不是左括号则存入postexp,注:此操作会将与右括匹配的左括号删除
}
exp++;
break;
case '+':
case '-':
while(!StackEmpty(s)) //栈不空时循环
{
GetTop(s,e); //取栈顶元素
if(e!='(')
{
postexp[i++]=e; //不为左括号就存入postexp
Pop(s,e); //出栈
}
else //e=='(' 时退出循环
break;
}
Push(s,*exp); //将该 '+'||'-' 入栈
exp++;
break;
case '*':
case '/':
while(!StackEmpty(s)) //栈不空时循环
{
GetTop(s,e); //去栈顶元素
if(e=='*'||e=='/') //把前面的 '*' || '/' 全部出栈
{ //原因:比'*'||'/'更高级的只有前面的'*'||'/'
postexp[i++]=e; //注:之所以不考虑前面的左括号是因为遇见'('时就会跳出循环
Pop(s,e);
}
else
break; //当e=='+'||e=='-'||e=='(' 时跳出循环
}
Push(s,*exp);
exp++;
break;
default : //处理数字字符
while(*exp>='0'&&*exp<='9')//数字直接存入postexp
{
postexp[i++]=*exp;
exp++;
}
postexp[i++]='#'; //用'#'标识一个数字的结束,放在外面是考虑到可能有二位数三位数等
}
}
while(!StackEmpty(s)) //exp已经扫描完毕
{
Pop(s,e); //将未出栈的运算符放在最后
postexp[i++]=e;
}
postexp[i]='\0'; //添加结束标识
DestroyStack(s); //销毁栈
}
double compvalue(char *postexp) //后缀式计算 compvalue(postexp);
{
double a,b,c,d,e;
lei *r;
InitStack(r);
while(*postexp!='\0')
{
switch(*postexp)
{
case '+':
Pop1(r,a);
Pop1(r,b); //取出运算符前面紧挨的两个数
c=b+a; //进行相关运算
Push1(r,c); //入栈,用于进行下次运算
break;
case '-':
Pop1(r,a);
Pop1(r,b);
c=b-a;
Push1(r,c);
break;
case '*':
Pop1(r,a);
Pop1(r,b);
c=b*a;
Push1(r,c额);
break;
case'/':
Pop1(r,a);
Pop1(r,b);
if(a!=0)
{
c=b/a;
Push1(r,c);
break;
}
else //除数为零
{
printf("\n除零错误!\n");
exit(0); //非正常结束进程
}
break;
default :
d=0;
while(*postexp>='0'&&*postexp<='9')
{
d=10 * d + *postexp - '0';
postexp++;
}
Push1(r,d); //将数字入栈
break;
}
postexp++;
}
GetTop1(r,e); //取栈顶元素,事实上此时栈中仅有一个元素
DestroyStack(r); //销毁栈
return e; //返回结果
}
栈的操作函数部分
//字符型函数
void InitStack(lei *&s) //初始化 InitStack(s);
{
s=(lei *)malloc(sizeof(lei));
s->next=NULL;
}
void DestroyStack(lei *&s) //销毁栈 DestroyStack(s);
{
lei *pre=s,*p=s->next; //pre指向头结点,p指向首节点
while(p!=NULL)
{
free(pre);
pre=p;
p=p->next;
}
free(pre); //此时pre指向尾节点
}
bool StackEmpty(lei *s) //判断是否为空栈 StackEmpty(s);
{
return(s->next==NULL);
}
void Push(lei *&s,char e) //进栈 Push(s,e);
{
lei *p;
p=(lei *)malloc(sizeof(lei));
p->a=e;
p->next=s->next; //头插法,将p节点插入作为首节点
s->next=p;
}
bool Pop(lei *&s,char &e) //出栈 Pop(s,e);
{
lei *p;
if(s->next==NULL) return false; //空栈的情况返回假
p=s->next;
e=p->a; //提取首节点值
s->next=p->next; //删除首节点
free(p); //释放被删除节点的存储空间
return true;
}
bool GetTop(lei *s,char &e) //栈顶元素提取 GetTop(s,e);
{
if(s->next==NULL) return false;
e=s->next->a;
return true;
}
//实型函数
void Push1(lei *&s,double e) //进栈 Push1(s,e);
{
lei *p;
p=(lei *)malloc(sizeof(lei));
p->b=e;
p->next=s->next; //头插法,将p节点插入作为首节点
s->next=p;
}
bool Pop1(lei *&s,double &e) //出栈 Pop1(s,e);
{
lei *p;
if(s->next==NULL) return false; //空栈的情况返回假
p=s->next;
e=p->b; //提取首节点值
s->next=p->next; //删除首节点
free(p); //释放被删除节点的存储空间
return true;
}
bool GetTop1(lei *s,double &e) //栈顶元素提取 GetTop1(s,e);
{
if(s->next==NULL) return false;
e=s->next->b;
return true;
}
版权声明:本文为dark_cy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。