2018年第14周-大话数据结构的笔记(栈与队列)

栈与队列

栈(stack)是限定仅在表尾进行插入和删除操做的线性表git

容许插入和删除的一端称为栈顶(top),另外一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。大话数据结构的程杰老师用“弹夹式手枪和左轮手枪”这个例子来比喻,很形象。

栈的插入操做,叫作进栈,也称压栈入栈
栈的删除操做,叫作出栈,也称弹栈数组

栈的抽象数据类型

对于栈来说,理论上线性表的操做特性它都具有,可因为它的特殊性,因此针对它的操做上会有变化。特别是插入和删除操做,咱们更名为push和pop。这对于Java的面向对象来讲可能体会比较深,如ArrayList和Vector都是继承抽象类AbstractList,而Vector又是Stack的父类,因此Stack是具备普通线性表的功能,但又具备本身push和pop的方法。。数据结构

ADT 栈(stack)  
Data
    同线性表。元素具备相同的类型,相邻元素具备前驱和后继关系。

Operation
    InitStack(*S);        //初始化操做,创建一个空栈S
    DestroyStack(*S);    //若栈存在,则销毁它  
    ClearStack(*S);        //将栈清空
    StackEmpty(S);        //若栈为空,返回true,不然返回false
    GetTop(S,*e);        //若栈存在且非空,用e返回S的栈顶元素
    Push(*S,e);            //若栈S存在,插入新元素e到栈S中并称为栈顶元素  
    Pop(*S,*e);            //删除栈S中栈顶元素,并用e返回其值  
    StackLength(S);        //返回栈S的元素个数
endADT

逆波兰表达式(Reverse Polish Notation, RPN)又称后缀表达式。是由波兰逻辑学家J.Lukasiewicz于1929年提出了另外一种表示表达式的方法,按此方法,每一运算符都置于其运算对象以后,故称为后缀表示。app

与后缀表达式对应的是中缀表达式,也就是咱们经常使用的9+(3-1)x3+10/2这种表达式,中缀表达式是二元运算符置于与之相关的两个运算对象之间。

后缀表达式的计算规则:
规则:从左到右遍历表达式的每一个数字和符号,遇到是数字就进栈,遇到符号就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终结果。反正运算符是不会进栈的。
举个栗子,如9 3 1 - 3 * + 10 2 / +步骤以下:code

  1. 初始化一个空栈,此栈用来对要运算的数字(操做数)进出使用;
  2. 后缀表达式的前三个都是数字,因此九、3 、1进栈;
  3. 接下来是减号-,因此将栈中的操做数1和操做数3出栈,操做数1做为减数,操做数3做为被减数。则就是3-1=2,而后再将2进栈;
  4. 接着是数字3进栈;
  5. 后面是乘号,也就是把操做数3和操做数2出栈,23=6,而后将6进栈;
  6. 接下来是加号+,因此把操做数6和9出栈,9+6=15,将15进栈;
  7. 接着是10与2两数字进栈;
  8. 后面是除号/,所以,栈顶的2与10出栈,10/2=5,将5进栈;
  9. 最后一个符号是加号+,因此将15和5出栈并相加,15+5=20,将20进栈;
  10. 遍历完毕,20出栈,栈变为空,20就是最终结果。

中缀表达式转后缀表达式(计算器实现原理):对象

规则是:从左到右遍历中缀表达式的每一个数字和符号,如果数字就输出,即为后缀表达式的一部分;若是是符号,则判断此符号与栈顶符号的优先级,若是栈顶元素是右括号或栈顶元素的优先级高于或等于栈顶符号(乘除优先加减),则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式位置。反正数字(操做数)和括号是不会进栈的。
举个栗子,将中缀表达式9+(3-1)x3+10/2转为后缀表达式9 3 1 - 3 * + 10 2 / + 步骤以下:继承

  1. 初始化一个空栈,用于对符号(操做符)进出栈使用;
  2. 第一个字符是数字9,输出9,后面是符号加号+,加号+进栈;
  3. 第三个字符是左括号“(”,依然是符号,因其只是左括号,还未匹配,故进栈;
  4. 第四个字符是数字3,输出3,总表达式为 9 3,接着是减号-,进栈;
  5. 接下来是数字1,输出1,总表达式为 9 3 1,后面符号是右括号“)”,此时,咱们须要去匹配以前的左括号“(”,因此栈顶依次出栈,并输出,直到左括号“(”出栈为止。此时左括号上方只有减号-,所以输出减号-。此时表达式为 9 3 1 -;
  6. 接着是字符是乘号×,因为乘号优先级高于栈顶元素(此时是加号+),此时将乘号×入栈。
  7. 接着字符是数字3,输出3,此时表达式为9 3 1 - 3;
  8. 跟着是字符是加号+,因为加号+优先级低于栈顶元素(此时是乘号×),因此栈中元素出栈并输出直到没有比当前字符优先级更低的符号,也就是输出乘号×和加号+,而后当前元素加号+则进栈,此时表达式为 9 3 1 - 3 * +;
  9. 接着字符是数字10,输出10,此时表达式为 9 3 1 - 3 * + 10;
  10. 接着是字符除号/,因为栈顶元素如今是加号,优先级低于除号/,因此除号/入栈;
  11. 接着是数字2,输出数字2,此时表达式为 9 3 1 - 3 * + 10 2;
  12. 遍历完毕,将栈内元素出栈,分别是除号/和加号+,此时表达式为 9 3 1 - 3 * + 10 2 / +为最终结果。

总结下:
将中缀表达式转化为后缀表达式(数字(操做数)和括号是不会进栈的);
将后缀表达式进行运算得出结果(运算符是不会进栈的);队列

队列

队列(queue)是只容许在一端进行插入操做,而在另一端进行删除操做的线性表
再次提起下,以增强记忆,既然时线性表,就说明能够用数组或链表的物理结构进行存储。get

队列是一种先进先出(First In First Out)的线性表,简称FIFO。容许插入的一端称为堆尾,容许删除的一端称为队头。

队列的抽象数据类型

一样是线性表,队列也有相似线性表的各类操做,不一样的就是插入数据只能在队尾进行,删除数据只能在队头进行。it

ADT 队列(Queue)
Data
    同线性表。元素具备相同的类型,相邻元素具备前驱和后继关系。

Operation
    InitQueue(*Q);        //初始化操做,创建一个空队列Q
    DestroyQueue(*Q);     //若队列Q存在,则销毁它
    ClearQueue(*Q);        //将队列Q清空
    QueueEmpty(Q);        //若队列Q为空,返回true,不然返回false    
    GetHead(Q,*e);        //若队列Q存在且非空,用e返回队列Q的队头元素
    EnQueue(*Q,e);        //若队列Q存在,插入新元素e到队列Q中并成为队尾元素
    Dequeue(*Q,*e);        //删除队列Q中队头元素,并用e返回其值
    QueueLength(Q);        //返回队列Q的元素个数

循环队列:把队列的头尾相接的顺序存储结构

总结

使用了栈和队列结合起来,能够写出一个简单的计算器,我用C写了一个,感兴趣能够点击下

参考:《大话数据结构》

相关文章
相关标签/搜索