第四篇 栈与队列(二)

一、队列的定义

  队列(queue)是只允许在一段进行插入操作,而在另一端进行删除操作的线性表,队列是一种先进先出(First in First Out)的线性表,简称为FIFO。而堆栈为先进后出的线性表(FILO)。允许插入的一端称为队尾,允许删除的一端称为队头。

  如图所示:

  

二、队列的抽象数据结构

  因为队列本身是线性表,因此具有线性表的所有特性。而作为先进先出的线性表,也有其自身的一些特性。

  如图所示:

  

三、循环队列

  在队列的顺序存储结构中,对队列进行插入操作,是在其队尾插入一个元素,可以一直添加到队列已满为止,算法复杂度为O(1),而当执行取出操作时,在队列的头部取出一个元素,同时其后面的元素依此向前移动一位。从而导致其算法复杂度为O(n)。其实这类似与我们日常排队买票的情景,当前面的人买到票以后,离开了,后面的所有等待购票的人依此向前前进一步。

  为了解决上面插入操作时后面的依此向前移动,我们提出了循环队列。

  循环队列:我们把头尾相接的顺序存储结构的队列称为循环队列。

四、循环队列的算法实现

采用空闲一个位置的方式,即N个元素空间的循环队列最多只能存放N-1个有效元素。这也是大多数教材的做法。
1) 循环队列初始化:front=rear=0;
2)入队操作:rear=(rear+1)%size;
3)出队操作:front=(front+1)%size;
4)判断是否为空队列:front==rear;
5)判断队列是否已满:front=(rear+1)%size;
6)遍历队列各元素。

  C#代码如下

 /// <summary>
    /// 循环队列的算法实现
    /// </summary>


    /*
     *算法描述 
     * 采用空闲一个位置的方式,即N个元素空间的循环队列最多只能存放N-1个有效元素。这也是大多数教材的做法。
        1) 循环队列初始化:front=rear=0;
        2)入队操作:rear=(rear+1)%size;
        3)出队操作:front=(front+1)%size;
        4)判断是否为空队列:front==rear;
        5)判断队列是否已满:front=(rear+1)%size;
        6)遍历队列各元素。
     * 
     */

    /*
     *参考资料
     *http://www.cnblogs.com/zhaoyl/archive/2012/09/20/2695136.html
     *http://blog.csdn.net/huangkq1989/article/details/5719529
     * 大话数据结构
     */


    public class CirculeQueue
    {
        /// <summary>
        /// 队列的头指针
        /// </summary>
        public int Front;

        /// <summary>
        /// 队列的尾指针
        /// </summary>
        public int Rear;

        /// <summary>
        /// 队列的数据
        /// </summary>
        public DataType[] Data;

        /// <summary>
        /// 队列的长度
        /// </summary>
        public int Length;

        /// <summary>
        /// 队列的最大值
        /// </summary>
        public int MaxSize;

        public CirculeQueue(int maxSize)
        {
            if (maxSize < 1)
                throw new ApplicationException("The queue size can not less than 1.");
            Data = new DataType[maxSize];
            MaxSize = maxSize;
        }

        /// <summary>
        /// 队列是否为空
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return Front == Rear;
        }

        /// <summary>
        /// 插入队列元素
        /// </summary>
        /// <param name="element">元素</param>
        public void Enqueue(DataType element)
        {
            //先判断队列是否已满
            if (Front == (Rear + 1) % MaxSize)
                throw new ApplicationException("The Queue is Full.");
            //在队尾插入元素,队尾指针向后移动一位
            Rear = (Rear + 1) % MaxSize;
            Data[Rear] = element;
            Length++;
        }

        /// <summary>
        /// 取出队头元素
        /// </summary>
        /// <returns></returns>
        public DataType Dequeue()
        {
            //先判断队列是否为空
            if (Front == Rear)
                throw new ApplicationException("The Queue is Empty.");
            //从队头取出元素
            Front = (Front + 1) % MaxSize;
            Length--;
            return Data[Front];
        }
    }

    /// <summary>
    /// 队列元素
    /// </summary>
    public class DataType
    {
        public object Data { get; set; }
    }

五、队列的链式存储结构

  队列的链式存储结构,其实就是线性表的单链表,只不不过它只能尾进头出。称为链队列。

  如图

  当队列为空时,front和rear都指向头节点。

  链队列的结构:如下图所示

  

链队列的算法实现

C#代码如下:

  /// <summary>
    /// 链队列的算法实现
    /// </summary>

    /*
     * 算法描述
     * 链队列属于单链表,因此具有单链表的特性
     *  1) 循环队列初始化:front=rear=null;
        2)入队操作:申请存储空间,将队尾指针移动一位;
        3)出队操作:指向队头指针;
     * 
     */

    /*
     * 参考资料
     * http://www.cnblogs.com/iwuyudong/archive/2010/12/20/2234111.html
     * http://blog.163.com/zhoumhan_0351/blog/static/39954227201001411343987/
     * http://www.cnblogs.com/navorse/articles/1889247.html
     * http://blog.chinaunix.net/uid-21768364-id-186080.html
     */
    public class LinkedQueue
    {
        /// <summary>
        /// 队列的头指针
        /// </summary>
        public Node FrontNode;

        /// <summary>
        /// 队列的尾指针
        /// </summary>
        public Node RearNode;

        /// <summary>
        /// 队列的数据
        /// </summary>
        public DataType[] Data;

        /// <summary>
        /// 队列的长度
        /// </summary>
        public int Length;

        public LinkedQueue()
        {

        }

        /// <summary>
        /// 队列是否为空
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return FrontNode == RearNode;
        }

        /// <summary>
        /// 插入队列元素
        /// </summary>
        /// <param name="element">元素</param>
        public void Enqueue(DataType element)
        {
            //创建新节点存放数据
            Node node = new Node();
            node.Data = element;
            node.NextNode = null;
            //将尾节点指向当前节点
            RearNode.NextNode = node;
            RearNode = node;
            Length++;
        }

        /// <summary>
        /// 取出队头元素
        /// </summary>
        /// <returns></returns>
        public DataType Dequeue()
        {
            //先判断队列是否为空
            if (FrontNode == RearNode)
                throw new ApplicationException("The Queue is Empty.");
            //将要删除的头节点赋给tempNode节点
            Node tempNode = FrontNode.NextNode;
            //将头结点的值赋给数据项data
            DataType data = tempNode.Data;
            //将原队头给点后继p->next 赋值给头给点后继.
            FrontNode = tempNode.NextNode;
            if (RearNode == tempNode)
                RearNode = FrontNode;
            return data;
        }
    }

    public class Node
    {
        /// <summary>
        /// 数据存储单元
        /// </summary>
        public DataType Data { get; set; }

        /// <summary>
        /// 下一个节点
        /// </summary>
        public Node NextNode { get; set; }
    }
原文地址:https://www.cnblogs.com/xiuyuanjing/p/4163079.html