栈与队列

来源:互联网 发布:java种方法是什么 编辑:程序博客网 时间:2024/06/05 23:01

栈(stack)

又可以被叫做堆栈,指的是一种只能从表的一个方向进行插入和删除元素的线性表。最先进入的元素被压在栈底,这样的结构限制了栈的元素进出方式为后进先出模式(LIFO)。

将元素放入堆栈中的操作叫做进栈,操作为push(a),而将元素从堆栈中删除的操作称为出栈,操作为pop(a)

若元素已将堆栈填满,又插入了新的元素,这样的现象叫做堆栈上溢;相应地若堆栈中不包含任何元素,而又出栈,那这样的现象就叫做堆栈下溢。上溢是一种错误行为,在程序中必须要避免,但是下溢则常被用来作为判断栈中元素是否已经全部出栈的条件。

堆栈的实现有很多方式,下面着重介绍顺序堆栈和链式堆栈。

  • 顺序堆栈
    顺序堆栈是顺序线性表的简单实现,要确定数组的哪一边作为栈顶,哪一边作为栈底。

    • 选择一:把数组的第0个位置作为栈顶

      根据线性表的函数,所有的插入(insert)和删除(remove)操作都在第0个位置的元素上进行。由于这时每次push(insert)或者pop(remove)操作都需要把当前栈中的所有元素在数组中移动一个位置,因此效率不高。如果栈中有n个元素,则时间代价为O(n)。

    • 选择二:当栈中有n个元素时把位置n-1作栈顶

      当向栈中压入元素时,把它们添加到线性表的表尾,成员函数pop也是删除表尾元素。在这种情况下,每次push或者pop操作的时间代价仅为O(1)。

  • 链式堆栈
    链式元素是采用链式线性表来进行实现的,它的元素只能在表头进行插入和删除。在链式存储结构中,不需要给出表头结点,因为其中惟一的已知栈顶指针top就是指向链式栈的第一个节点,也就是我们的栈底。

堆栈的基本运算有六种:判断堆栈空、堆栈初始化、判断堆栈满(仅限于顺序存储的情况下),入栈元素、出栈元素、取栈顶元素。在入栈时需要考虑:堆栈初始化,然后判断堆栈是否为满,如果不满,则可以插入元素(入栈);出栈时,需要考虑的步骤是:判断堆栈是否为空,如果不空,删除元素(出栈),出栈之前,保存栈顶元素。


队列(queue)

队列是一种只能从表的一个方向进入,另一个方向出的线性表。队列的概念与我们日常生活中的队列的概念很相似。这样的存储方式限定了先进入的元素一定是最先出队的,所以队列的进出方式遵循的是先进先出的规则(FIFO)。
同样,队列的存储也有两种方式:顺序存储和链式存储。

  • 顺序队列
    顺序队列实际上是运算受限的顺序表,必须用一个向量空间来存放当前队列中的元素。由于队列的队头和队尾的位置是变化的,因而要设置两个指针front(头指针)和和rear(尾指针),它们的初值在队列初始化时可以置为0。入队时将新元素插入rear所指的位置,然后将rear加1(即:rear指针指向队列最后一个元素的后一位)。出队时,删去front所指的元素,然后将front加1并返回被删元素。由此可见,当头尾指针相等时队列为空。在非空队列里,头指针始终指向队头元素,而尾指针始终指向队尾元素的下一个位置。

    那么我们其实已经看出问题了,当头指针不断删除元素,进队的元素只能往后面存储,之前的位置都是空的,这就造成了空间的浪费。这种现象成为假上溢。为了解决假上溢的问题,可以采用循环队列(circular queue)来存储。

    • 循环队列的使用

      假设向量的空间是m,只要在入出队列时,将队首和队尾的指针对m做求模运算即可实现队首和队为指针的循环,即队首和队尾指针的取值范围是0到m-1之间。

      入队时:rear=(rear+1)% maxsize
      出队时:front=(front+1)% mixsize

      但是队空和队满的条件是相同的,都是front=rear。那么如何区分队满和队空呢?

      • 方法一:设置浪费一个空间单元,假定rear指向的是刚刚插入元素的位置,front指向刚刚删除元素的位置。入队时,若(rear+1) % maxsize=front,则队满;出队时,若front=rear,则队空。
      • 方法二:设定一个变量来表示队列中的元素个数,利用该变量的值与队列的最大容量比较,如果该变量的值与最大容量相等,则表示队满,如果该变量的只为0,此时表示队列为空。
  • 链式队列
    链队列的存储结构基本和线性表的定义相同,不过需要在结构中指明的是队首和队尾的数据类型不再是整型而是指针类型。

队列的基本运算中有六种:判断队空、队列初始化、判断队列满(仅限于顺序存储的情况下),入队元素、出队元素、取队首元素等,而入队时需要操作的步骤是:初始化,然后判断队列是否为满,如果不满,则可以插入元素(入队);出队时,需要考虑的操作步骤是:判断队列是否为空,如果不空,删除元素(出队),出队之前,保存队首元素。也就是说,队列的入出队运算包含了其他的六种基本运算,取队首元素的运算,只是不用修改队首的指针而已。

0 0
原创粉丝点击