数据结构之堆栈

本文介绍了堆栈的基本概念,包括其定义、特点及基本运算,并详细讲解了顺序栈和链栈的实现方式。此外,还深入探讨了如何利用堆栈进行表达式的求值和转换,包括中缀表达式和后缀表达式的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迷茫,是青春最真实的状态;但奋斗,才是青春的主基调;努力是打败焦虑的绝好方法!


堆栈定义以及基本运算

堆栈: 堆栈,重点在,是限制在表的一端进行插入和删除的线性表。允许插入、删除的这一端称为栈顶,另一个固定端称为栈底。

特点:后入先出,先入后出。适用于正序输入,逆序输出。

栈又称为后进先出的线性表,简称LIFO表。

栈的基本运算

  • 构造栈:Init_Stack
  • 判空栈:Empty_Stack
  • 压入栈:Push_Stack
  • 压出栈:Pop_Stack
  • 读栈顶元素:Top_Stack

基本运算的具体实现

顺序栈

  • 置空栈
Stack *Init_Stack()
  { Stack *s;
  s = (Stack*)malloc(sizeof(Stack));   //申请栈的空间
  s -> top = -1;                       //初始化栈顶指针
  return s;
  }
  • 判栈空
int Empty_Stack(Stack *s)
   {if(s->top==-1) return 1;
   else return 0;
   }
  • 入栈
int Push_Stack(Stack *s,datatype x)
    {if(s->top==MAXSIZE-1)  return 0;   //栈满不能入栈
     else{ s->top++;
           s->data[s->top] = x;
           return 1;
           }
     }
  • 出栈
int Pop_Stack(Stack *s,datatype *x)
    {if(Empty_Stack(s)) return 0;   //栈空不能出栈
     else{*x=s->data[s->top];       //保存栈顶元素
          s->top--;                 //更新栈顶指针
          return 1;                 
          }
     }
  • 取栈顶元素
int Top_Stack(Stack *s,datatype *x)
    {if(Empty_Stack(s)) return 0;   //栈空无元素
     else {*x = s->data[s->top];    //保存栈顶元素
           return 1;
           }
     }

链栈

定义栈顶指针变量top:LinkStack top,指向栈顶。

  • 置空栈

栈顶指针指向空即可,top = null;

  • 判栈空
int Empty_LinkStack(LinkStack top)
   {if(top==NULL) return 1;
   else return 0;
   }
  • 入栈
LinkStack Push_LinkStack(LinkStack top,datatype x)
    {StackNode *p;
     p = (StackNode *)malloc(sizeof(StackNode));  //申请节点空间
     p -> data = x;       //将要加入的数值加入到新开辟的节点的数值域
     p -> next = top;     //让该节点指向栈顶,即加入到栈顶下方
     top = p;             //栈顶指针指向该节点,即该节点为栈顶
     return top;          //返回栈顶,即返回新加入的节点
     }
  • 出栈
LinkStack Pop_LinkStack(LinkStack top,datatype *x)
    {StackNode *p;
     if(top==NULL) return NULL;   //栈空,无法出栈
     else {*x = top->data;    //保存栈顶元素
           p = top;           //p为栈顶
           top = top->next;   //栈顶下移
           free(p);           //释放p的空间
           return top;
           }
     }

堆栈应用

表达式求值

注意:左括号在栈外优先级最高,栈内优先级最低。

中缀表达式求值

例子

给一个中缀表达式,输出计算得到的值。
7*2*2-5+1-5+3-4
求解结果为18

解决步骤

  1. 设定两个栈s1和s2,s1用于存储运算对象,s2用于存储运算符。
  2. 从左到右扫描整个表达式,如果是运算对象,压入s1。
  3. 如果是运算符,则要分情况讨论:
    1. s2为空栈,直接压入栈中;
    2. 当前运算符的优先级高于栈顶的优先级,压入栈
    3. 当前运算符的优先级低于栈顶的优先级,s1出栈两个数据,s2出栈栈顶运算符,进行计算,结果压入s1。
    4. 当前运算符还未入栈,继续循环第3步骤(整个第3步骤,不是里面的第3步骤)。
    5. 如果运算符为右括号,则持续出栈,直到s2中遇到左括号为止,然后去掉这一对括号。
  4. 扫描完整个中缀表达式后,如果s2不为空,则依次从s1中出栈两个数据进行计算。结果压入栈中;循环往复,直到s2为空。最后s1中的数据就是所求的结果。

表格分析

读字符对象栈s1算符栈s2说明
777入栈s1
*7(**入栈s2
27,2(*2入栈s1
*14(做7*2=14,结果入栈s1
14(**入栈s2
214,2(*2入栈s1
-28做14*2=28,结果入栈 s1
28(--入栈s2
528,5(-5入栈s1
+23做28-5=23,结果入栈s1
23(++入栈s2
123,1(+1入栈s1
-24做23+1=24,结果入栈s1
24(--入栈s2
524,5(-5入栈s1
+19做24-5=19,结果入栈s1
19(++入栈s2
319,3(+3入栈s1
-22(做19+3=22,结果入栈s1
22(--入栈s2
422,4(-4入栈s1

扫描至表达式末尾,算符栈中还有算符,依次出栈,进行计算,所以22-4=18。

后缀表达式求值

例子

给一个后缀表达式,输出计算得到的值。
32422*+13*-^*5-
求解结果为91

解决步骤

  1. 使用一个对象栈s1,来存储运算对象。
  2. 从左到右扫描表达式。
  3. 遇到运算对象,就入栈s1,遇到运算符,就从s1中取出两个运算对象,进行计算,结果压入s1。

表格分析

读字符对象栈s1说明
333入栈s1
23,22入栈s1
43,2,44入栈s1
23,2,4,22入栈s1
23,2,4,2,22入栈s1
*3,2,4,4计算2*2,将结果4入栈s1
+3,2,8计算4+4,将结果8入栈s1
13,2,8,11入栈s1
33,2,8,1,33入栈s1
*3,2,8,3计算1*3,将结果3入栈s1
-3,2,5计算8-3,将结果5入栈s1
^3,32计算2^5,将结果32入栈s1
*96计算3*32,将结果96入栈s1
596,55入栈s1
-91计算96-5,将结果91入栈s1

中缀表达式转后缀表达式

例子

输入一个中缀表达式,转换成后缀表达式。
中缀表达式:3*2^(4+2*2-1*3)-5
转换为后缀表达式:32422*+13*-^*5-

解决步骤

  • 初始化两个栈,对象栈s1,算符栈s2。

  • 从左至右扫描中缀表达式。

  • 遇到运算对象时,入栈s1。

  • 遇到运算符时,将其与s2的栈顶作比较:

      1. 若s2为空栈,或者s2栈顶运算符为“(”,则入栈s2。
      2. 若运算符的优先级高于栈顶运算符,入栈s2。
      3. 否则,将s2的栈顶运算符弹出,入栈s1,再次循环进行与当前栈顶运算符比较。
    
  • 遇到括号时:

      1. 若是“(”,入栈s2。
      2. 若是“)”,则依次弹出s2中的栈顶运算符并压入s1中,直到遇到左括号为止,此时将这一对括号丢弃。
    
  • 重复上述除初始化栈之外的所有操作,直到表达式扫描至最右边。

  • 若扫描结束后,算符栈s2中还有剩余的字符,则全部出栈,压入s1中。

  • 将s1中的元素依次弹出,取逆序,得到后缀表达式。

表格分析

读字符对象栈s1算符栈s2说明
33(3入栈s1
*3(**入栈s2
23,2(*2入栈s1
^3,2(*^^入栈s2
(3,2(*^((入栈s2,(在栈外优先级最高
43,2,4(*^(4入栈s1
+3,2,4(*^(++入栈s2,(在栈内优先级最低
23,2,4,2(*^(+2入栈s1
*3,2,4,2(*^(+ **入栈s2
23,2,4,2,2(*^(+ *2入栈s1
-3,2,4,2,2,*,+(*^(-*+出栈s2,压入s1,-入栈s2
13,2,4,2,2,*,+,1(*^(-1入栈s1
*3,2,4,2,2,*,+,1(*^(- **入栈s2
33,2,4,2,2,*,+,1,3(*^(- *3入栈s1
)3,2,4,2,2,*,+,1,3, *,-(*^遇到右括号,算符栈栈顶持续出栈,直到遇到左括号为止,丢弃这一对括号。
-3,2,4,2,2,*,+,1,3, *,-,^, *(-优先级低于栈顶,栈顶出栈;栈为空,-入栈s1
53,2,4,2,2,*,+,1,3, *,-,^, *,5(-5入栈s1
结束符3,2,4,2,2,*,+,1,3, *,-,^, *,5,-(扫描到末尾,s2中还有字符,出栈s2,压入s1

后缀表达式即需要出栈s1中所有元素,取逆序即可,所以后缀表达式为32422 * +13 * -^ * 5-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值