zoukankan      html  css  js  c++  java
  • 数据结构学习笔记——栈和队列

    栈和队列

    栈(先进后出线性表)

         栈是一种只能在一端进行插入或删除操作的线性表。表中允许进行插入、删除操作的一端称为栈顶。
         栈顶的当前位置是动态的,栈顶的当前位置由一个称为栈顶指针的位置指示器指示。表的另一端称为栈底。
         当栈中没有数据元素时,称为空栈。
         栈的插入操作通常称为进栈或入栈,栈的删除操作通常称为退栈或出栈。
       
         栈的顺序存储结构称为顺序栈,通常利用一个一维数组实现和一个记录格顶位置的变量组成。
         栈的链接实现称为栈链,通常利有一个单链表实现,其中单链表可带一个头节点,也可不带一个头结点。
    --------------------------------------------------------------------------------------------------------------
    例 假设表达式中允许包含三种括号:圆括号、方括号和大括号。编写一个算法判断表达式中的括号是否正确配对。 
    解: 设置一个括号栈,扫描表达式:遇到左括号(包括(、[和{)时进栈,遇到右括号时,若栈是相匹配的左括号,则出栈,否则,返回0。
        若表达式扫描结束,栈为空,返回1表示括号正确匹配,否则返回0。

    ----------------------
    栈在实际中有广泛的应用

    栈的应用举例:

    一、    表达式求值
          概念:后缀表达式
          所谓后缀表达式,就是将运算符放在操作数后面,如1+2*3(中缀表达式)的后缀表达为123*+,在后缀表达式中已经考虑了运算符的优先级,没有括号,只有操作数和运算符。
          在程序语言中,运算符位于两个操作数中间的表达式称为中缀表达式。例如:
                    1+2*3
          就是一个中缀表达式,中缀表达式是最常用的一种表达式方式。对中缀表达式的运算一般遵循“先乘除,后加减,从左到右计算,先括号内,后括号外”的规则。因此,中缀表达式不仅要依赖运算符优先级,而且还要处理括号。
          所谓后缀表达式,就是运算符在操作数的后面,如1+2*3的后缀表达式为123*+。在后缀表达式中已考虑了运算符的优先级,没有括号,只有操作数和运算符。
          对后缀表达式求值过程是:从左到右读入后缀表达式,若读入的是一个操作数,就将它入数值栈,若读入的是一个运算符op,就从数值栈中连续出栈两个元素(两个操作数),假设为x和y,计算x op y之值,并将计算结果入数值栈;对整个后缀表达式读入结束时,栈顶元素就是计算结果。
          算术表达式求值过程是:先将算术表达式转换成后缀表达式,然后对该后缀表达式求值。
        
    二、    求解迷宫问题(穷举求解) 亦采用顺序栈(当然亦可用栈链)
          特点:不一定是最优解
          求迷宫问题就是求出从入口到出口的路径。在求解时,通常用的是“穷举求解”的方法,即从入口出发,顺某一方向向前试探,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续试探,直至所有可能的通路都试探完为止。
         
    三、    进制转换(运用短除法)
          

    队列(后进先出线性表)

           队列简称队,它也是一种运算受限的线性表,其限制仅允许在表的一端进行插入,而在表的另一端进行删除。
           我们把进行插入的一端称做队尾(rear),进行删除的一端称做队首(front)。
           向队列中插入新元素称为进队或入队,新元素进队后就成为新的队尾元素;从队列中删除元素称为出队或离队,元素出队后,其后继元素就成为队首元素。
    队列的顺序存储结构
           为了能够充分地使用数组中的存储空间,把数组的前端和后端连接起来,形成一个环形的顺序表,即把存储队列元素的表从逻辑上看成一个环,称为环形队列。
    怎样区分这两者之间的差别呢?在入队时少用一个数据元素空间,以队尾指针加1等于
    队首指针判断队满,即队满条件为:
    (q->rear+1% MaxSize==q->front
    队空条件仍为:
    q->rear==q->front
    入队运算:
    q->rear = (q->rear+1% MaxSize
    出队运算:
    q->front = (q-> front +1% MaxSize
    例 什么是队列的上溢现象和假溢出现象?解决它们有哪些方法?
    答: 在队列的顺序存储结构中,设头指针为front,队尾指针rear,队的容量(存储空间的大小)为MaxSize。当有元素加入到队列时,若 rear=MaxSize(初始时rear=0)则发生队列的上溢现象,该元素不能加入队列。
          
        特别要注意的是队列的假溢出现象:队列中还有剩余空间但元素却不能进入队列,造成这种现象的原因是由于队列的操作方法所致。
    解决队列上溢的方法有以下几种:
        (1) 建立一个足够大的存储空间,但这样做会造成空间的使用效率降低。
        (2)  当出现假溢出时可采用以下几种方法:
        ①采用平移元素的方法:每当队列中加入一个元素时,队列中已有的元素向队头移动一个位置(当然要有空闲的空间可供移动);
        ②每当删除一个队头元素时,则依次移动队中的元素,始终使front指针指向队列中的第一个位置;
        ③采用环形队列方式:把队列看成一个首尾相接的环形队列,在环形队列上进行插入或删除运算时仍然遵循“先进先出”的原则。


        对于顺序队列来说,如果知道队首元素的位置和队列中元素个数,则队尾元素所在位置显然是可以计算的。也就是说,可以用队列中元素个数代替队尾指针。编写出这种循环顺序队列的初始化、入队、出队和判空算法。
        当已知队首元素的位置front和队列中元素个数count后:
        队空的条件为:count==0
        队满的条件为:count==MaxSize
        计算队尾位置rear:    
        rear=(front+count+MaxSize)%MaxSize
        对应的结构如下:
    typedef struct
    {   ElemType data[MaxSize];
        
    int front;    /*队首指针*/
        
    int count;    /*队列中元素个数*/
    }  QuType;        
    /*队列类型*/
        
        例:如果允许在环形队列的两端都可以进行插入和删除工作(这样的队列称为双端对列),若采用前面定义的SqQueue队列类型,编写“从队尾删除”和从队头插入的算法。


          队列的链式存储结构
          队链,采用一个单链表结构,有一个指向表头和表尾的指针组成
          特点:无内存限制。
          扩展:想想既然是一个单链表结构,可否用静态链表代替呢?(不行,因为静态链表有空间大小限制,因此不能实现队列的链式存储结构,可以将其构成一个循环结构,但这又没有循环队列,算法复杂度低)。
         链队亦可带一个头结点,也可不带一个头结点(一般情况下是带一个头节点的)


    队列的应用:
    一、    运用队列求解约瑟夫环问题(报到出列的出列,未报到出列的出列并加到队列最右边继续)[整个过程,以出列操作来驱动循环]
    二、    求解迷宫问题(得出的是最优解[最短路径])亦采用顺序队列(当然亦可用队链)
              使用一个队列Qu记录走过的方块,该队列的结构如下:
    struct
    {       
    int i,j;    /*方块的位置*/
            
    int pre;  /*本路径中上一方块在Qu中的下标*/
    } Qu[MaxSize];
    int front=-1,rear=-1;    /*队首指针和队尾指针*/
       
        这里使用的队列Qu不是环形队列(因为要利用出队的元素找路径),因此在出队时,不会将出队元素真正从队列中删除,因为要利用它输出路径。
       
        搜索从(1,1)到(M-2,N-2)路径
        (1)  首先将(1,1)入队;
        (2)  在队列Qu不为空时循环:出队一次(由于不是环形队列,该出队元素仍在队列中),称该出队的方块为当前方块,front为该方块在Qu中的下标。
          ①如果当前方块是出口,则输出路径并结束。
          ②否则,按顺时针方向找出当前方块的四个方位中可走的相邻方块(对应的mg数组值为0),将这些可走的相邻方块均插入到队列Qu中,其pre设置为本搜索路径中上一方块在Qu中的下标值,也就是当前方块的front值,并将相邻方块对应的mg数组值置为-1,以避免回过来重复搜索。
         (3)  若队列为空仍未找到出口,即不存在路径。

         [与栈的比较]
         栈中用方向来控制查找路径,而队列是固定的控制查找路径
         栈中从下标0,打印到尾,是找到的路径,而队列中,从尾通过pre回溯到头并重将设置pre一个特殊置,再从队列头到队列尾搜索出特殊值所在的路径。
  • 相关阅读:
    c++深拷贝与浅拷贝
    c++构造函数的explicit
    c++虚函数和虚函数表
    c++重载、重写、隐藏(重定义)
    c++传值、传指针、传引用
    ASP.Net Core API 学习の中间件
    WPF中String Format的用法
    ASP.Net Core API 全局处理异常
    989. Add to Array-Form of Integer
    1014. Best Sightseeing Pair
  • 原文地址:https://www.cnblogs.com/_programmer/p/1569911.html
Copyright © 2011-2022 走看看