栈是一种典型的受限线性表,关于线性表的链式存储结构
数据结构:链表总结:https://blog.csdn.net/qq_41605114/article/details/104589975
栈的应用,更多体现在如何设置结点,如何设置头结点内容,和如何合理化的适当增添接口,下面的内容来源《大话数据结构》
赘述了中缀表达式转化为后缀表达式,和后缀表达式在计算机中是如何被应用的。
(图源:大话数据结构)
此处 输出结果如下:
只展示中缀表达式如何变成后缀表达式:
链表的基本结构如下:结点类型中成员较多,因为知道要储存数据的类型,就没有必要使用void *了。
char item保存运算符和没有数字,int grade保存的是 运算符的优先级,int Number是给字符数字转化为数值后,预留的空间
//stack 链式 头结点入栈,头结点出栈
struct StackNode
{
char Item;//运算符本身
int grade;//运算符优先级
int Number;//数字
StackNode * next;
};
//栈的性质
struct StackProperty
{
StackNode header;
int size;
};
//初始化
StackProperty * Insert_Stack();
//进栈
void Push_Stack(StackProperty * stacklist,StackNode * PushData);
//查看栈顶元素
StackNode * CheackTop_Stack(StackProperty * stacklist);
//出栈
void Pop_Stack(StackProperty * stacklist);
//销毁
void Destroy_Stack(StackProperty * stacklist);
//判断是不是运算符
bool BoolJudgeOperator(char data);
//运算符优先级
int ItemJudegOperator(char data);//判断运算符
以下为栈的接口,多了一个接口,就是常看栈顶元素,只是输出栈顶元素,并不出栈
//初始化
StackProperty * Insert_Stack()
{
StackProperty * mystack = new StackProperty;
mystack->size = 0;
mystack->header.next = nullptr;
return mystack;
}
//进栈
void Push_Stack(StackProperty * stacklist,StackNode * PushData)
{
if(nullptr == stacklist)
return;
if(nullptr == PushData)
return;
StackNode * mydata = new StackNode;
//将要插入的内容 赋值给新分配好的空间
mydata->grade = PushData->grade;
mydata->Item = PushData->Item;
mydata->next = PushData->next;
mydata->next = stacklist->header.next;//更新插入元素的后驱
stacklist->header.next = mydata;//更新头指针的指向
stacklist->size++;
// qDebug()<<"进栈元素"<<mydata->Item;
}
//出栈
void Pop_Stack(StackProperty * stacklist)
{
if(nullptr == stacklist)
return;
StackNode * myDel = stacklist->header.next;//第一个结点,也就是要出栈的结点
stacklist->header.next = myDel->next;//更新头结点后驱
myDel->next = nullptr;//更新出栈结点的后驱
stacklist->size--;
delete myDel;
}
//查看栈顶元素
StackNode * CheackTop_Stack(StackProperty * stacklist)
{
if(nullptr == stacklist)
return nullptr;
StackNode * myDel = stacklist->header.next;//第一个结点,也就是要出栈的结点
return myDel;//直接将这个值转化为用户数据类型即可调用其中的数字或者运算符
}
//销毁
void Destroy_Stack(StackProperty * stacklist)
{
if(nullptr == stacklist)
return;
delete stacklist;
}
中缀表达式转化为后缀表达式的思路:
- 数字,直接进栈
- 左括号运算符,直接进行
- 右括号运算符,从栈顶开始依次出栈,直到左括号出线,结束
- 要进栈的运算符和栈顶运算符比较,优先级高于栈顶运算符,进栈。
- 优先级低于或等于栈顶运算符,栈顶运算符出栈,之后重复操作,继续进行优先级比较,完全比完后,该运算符进栈
- 循环完整个表达式,完成所有操作后,最后不要忘了,栈内结点全部出栈,作为表达式最后的输出
具体实现如下,通过优先级进行判断,运算符优先级规定,判断是数字还是运算符的接口,如下接口所示:
int ItemJudegOperator(char data)//判断运算符
{
if(data == '+'||data == '-')
return 2;
else if(data == '/'||data == 'x')
return 3;
else if(data == '(')
return -1;
else if(data == ')')
return 1;
else
return 0;
}
bool BoolJudgeOperator(char data)//判断运算符
{
if(data == '+'||data == '-'||data == '/'||data == 'x'||data == '('||data == ')')
return true;//是
else
return false;
}
下面是用代码实现以上逻辑
第二个while中的三个if else 就是完全遵循中缀转后缀的法则进行的,运算符的优先级是通过数字来分档判断的,完整版见后面
while( MathInfix[SizeOFLoop]!='\0' )
{
//先判断是不是数字
if( BoolJudgeOperator( MathInfix[SizeOFLoop] ) )//判断是不是操作符号
{
int IntFlagForItem = ItemJudegOperator(MathInfix[SizeOFLoop]);
while(MyStack->header.next != nullptr)//看看有没有要出栈的
{
//和栈顶元素比优先级
StackNode * TopItem = CheackTop_Stack(MyStack);
if(IntFlagForItem == -1||IntFlagForItem>TopItem->grade)//左括号||优先级高 进栈
{
break;//直接让该运算符进栈
}
else if(IntFlagForItem == 1)//右括号
{
break;
}
//要入栈运算符的优先级低于栈顶元素,栈顶输出,并且循环,直到优先级
else if(IntFlagForItem < TopItem->grade||IntFlagForItem == TopItem->grade)
{
break;
}
}
if(IntFlagForItem != 1)//右括号
{
//出栈的出完了,进栈
StackNode S = {MathInfix[SizeOFLoop],ItemJudegOperator(MathInfix[SizeOFLoop]),0,nullptr};
Push_Stack(MyStack,&S);
//这个要分配空间了,在销毁的部分要求销毁
}
执行程序完整版本
char MathInfix[] = "9+(3-1)x3+10/2";
StackProperty * MyStack = Insert_Stack();//创建头结点
StackProperty * ResultStack = Insert_Stack();//创建头结点,存放后缀表达式
int SizeOFLoop = 0;//循环次数
while( MathInfix[SizeOFLoop]!='\0' )
{
//先判断是不是数字
if( BoolJudgeOperator( MathInfix[SizeOFLoop] ) )//判断是不是操作符号
{
int IntFlagForItem = ItemJudegOperator(MathInfix[SizeOFLoop]);
while(MyStack->header.next != nullptr)//看看有没有要出栈的
{
//和栈顶元素比优先级
StackNode * TopItem = CheackTop_Stack(MyStack);
if(IntFlagForItem == -1||IntFlagForItem>TopItem->grade)//左括号||优先级高 进栈
{
break;//直接让该运算符进栈
}
else if(IntFlagForItem == 1)//右括号
{
//循环出栈,直到‘(’也出栈
while(MyStack->header.next != nullptr)
{
//栈顶元素
StackNode * Temp_TopItem = CheackTop_Stack(MyStack);
if(Temp_TopItem->Item == '(')
{
//左括号出栈
Pop_Stack(MyStack);
break;//直接跳出循环
}
else
{
//栈顶出栈
StackNode * ItemForPostfit = CheackTop_Stack(MyStack);
//输出
StackNode S_Result = {ItemForPostfit->Item,ItemForPostfit->grade,0,nullptr};
Push_Stack(ResultStack,&S_Result);
//释放结点
Pop_Stack(MyStack);
}
}
break;
}
//要入栈运算符的优先级低于栈顶元素,栈顶输出,并且循环,直到优先级
else if(IntFlagForItem < TopItem->grade||IntFlagForItem == TopItem->grade)
{
while(MyStack->header.next != nullptr)//栈空,则不再继续
{
//栈顶元素
StackNode * Temp_TopItem = CheackTop_Stack(MyStack);
//确定栈顶元素的优先级
int Temp_IntFlagForItem = ItemJudegOperator(Temp_TopItem->Item);
if(IntFlagForItem < Temp_IntFlagForItem||IntFlagForItem == Temp_IntFlagForItem)
{
//栈顶元素需要输出
//栈顶出栈
StackNode * ItemForPostfit = CheackTop_Stack(MyStack);
//输出
StackNode S_Result = {ItemForPostfit->Item,ItemForPostfit->grade,0,nullptr};
Push_Stack(ResultStack,&S_Result);
//释放结点
Pop_Stack(MyStack);
}
else if(IntFlagForItem>Temp_IntFlagForItem)
{
break;//插入元素的优先级不等于也不小于,也就是大的时候,出栈
}
}
break;
}
}
if(IntFlagForItem != 1)//右括号
{
//出栈的出完了,进栈
StackNode S = {MathInfix[SizeOFLoop],ItemJudegOperator(MathInfix[SizeOFLoop]),0,nullptr};
Push_Stack(MyStack,&S);
//这个要分配空间了,在销毁的部分要求销毁
}
}
else//不是的话,就是数字,数字是要输出的
{
//在输出字符串中保存该内容
StackNode S_Result = {MathInfix[SizeOFLoop],0,0,nullptr};
Push_Stack(ResultStack,&S_Result);
}
SizeOFLoop++;
}
qDebug()<<"将栈中结点全部弹出,添加到输出中,然后再销毁";
while(MyStack->header.next != nullptr)
{
//栈顶出栈
StackNode * ItemForPostfit = CheackTop_Stack(MyStack);
//输出
StackNode S_Result = {ItemForPostfit->Item,ItemForPostfit->grade,0,nullptr};
Push_Stack(ResultStack,&S_Result);
//释放结点
Pop_Stack(MyStack);
}
char result[ResultStack->size+1];
result[ResultStack->size] = '\0';
int intexforresult = ResultStack->size - 1;
while(ResultStack->header.next != nullptr)
{
//栈顶出栈
StackNode * Result_ItemForPostfit = CheackTop_Stack(ResultStack);
//输出
qDebug()<<Result_ItemForPostfit->Item;
result[intexforresult] = Result_ItemForPostfit->Item;
intexforresult--;
//释放结点
Pop_Stack(ResultStack);
}
qDebug()<<result;
qDebug()<<"销毁";
Destroy_Stack(MyStack);
Destroy_Stack(ResultStack);