编程基础 - 队列 (Queue)

本文详细介绍了队列的基本概念,包括FIFO原则和主要操作,并通过C++展示了数组型、循环型和链式队列的实现,包括初始化、入队、出队等方法。此外,还讨论了队列在实际应用中的例子。

编程基础 - 队列 (Queue)

返回分类:全部文章 >> 基础知识

本文意指简明扼要的描述队列,并用C++从零到有的实现栈。

需要一定的数据结构与程序语言的基础,尤其是要了解什么是顺序表。



1 队列的简介(Introduction of Queue)

  • 定义:队列是一种只允许在一端插入,另一端删除的特殊线性表

    • 允许插入的一端称为后端(Back/Rear)或队尾(Tail)
    • 允许删除的一端称为前端(Front)或队头(Head)
    • 插入操作称为进队或入队(Enqueue)
    • 删除操作称为退队或出队(Dequeue)
  • 限制:只允许在队头删除,队尾插入

  • 运算规则(特点):先进先出(First-In-First-Out,FIFO)或后进后出(Last-In-Last-out,LILO)


2 队列的主要方法(Main Methods of Queue)

队列的主要操作包括:

  • 初始化(Initialize)

  • 入队(Enqueue):插入元素;

  • 出队(Dequeue):如果队列中有元素,删除队头元素;

  • 获取队头元素(GetFront):如果队列不为空,获取队头元素;

  • 清空队列(Clear):如果队列不为空,则删除所有元素;

  • 判断队列空(IsEmpty):栈空返回true,否则返回false


3 队列的实现(C++ Code)

虽然在各种高级语言中,队列已经都被实现了:

  • 在C++中,使用栈需要加入#include <queue>

  • 在C#中,使用栈需要加入using System.Collection.Generic;

但在这里为了更好的理解它,我们将用C++自己实现栈

提示:以下代码编译器为VC++,属性__declspec(property...)代码在其它编译器可能不通用,如果用其它编译器可删除这一行,直接使用方法代替。

3.1 队列的抽象类(Abstract Class)

首先,我们新建一个头文件起名为Queues.h。它将包含如下内容:

  • 一些需要的常量(主要是顺序结构需要):

    • 队列的默认数组长度
    • 对立的默认数组长度增长率
  • 一个队列的模板抽象类:包含了队列的主要方法的虚函数。

  • 一些需要的包含库(#include)

我们同时为这些内容放入 命名空间Queues(之后所有代码都在它之中) 中:

#pragma once

#include <stdexcept> // Build-in exceptions

namespace Queues
{
    constexpr int DEFAULT_MAX_COUNT = 255; // Max Count of Sequential Structure
    constexpr int DEFAULT_INCREAMENT = 16; // Increament of Sequential Structure

    template<typename T>
    class AbstractQueue
    {
        public: // Constructor
        virtual ~AbstractQueue()
        {
        };

        public: // public Properties
        inline virtual int GetCount() = 0;
        __declspec(property(get = GetCount)) int count;

        public: // public Methods
        virtual void Enqueue(T item) = 0;
        virtual T Dequeue() = 0;
        virtual T Front() = 0;
        virtual T Peek();
        virtual void Clear() = 0;
        virtual bool Empty() = 0;
    };

    template<typename T>
    T AbstractQueue<T>::Peek()
    {
        return Front();
    }
}
  • #include <stdexcept>:程序异常库,里面有许多常用的异常错误信息

  • DEFAULT_MAX_COUNT:数组队列的默认长度;

  • DEFAULT_INCREAMENT:数组队列的默认增长长度;

  • template<typename T> class AbstractQueue:对立的模板抽象类(T为元素的类型)

    • int GetCount()int count:是一个属性方法,获取队列内元素个数
    • void Enqueue(T item):入队
    • T Dequeue():出栈
    • T Front():获取队头元素
    • void Clear():清空队列
    • bool Empty():队列是否为空

Tips
constexpr int可以替换成#define

  • #define DEFAULT_MAX_COUNT 255
  • #define DEFAULT_INCREAMENT 16

有了基类之后,我们来完成一些常见的队列形式。

3.2 数组型队列(Queue Using Array)

在数组存储方式中,数组存储数据的主要类型。而我们在进行队列操作时,需要两个变量分别指向队头与队尾,从而数组型结构需要的变量:

  • 元素数组:存储元素

    • 数组初始化的长度
    • 当数组满时,需要增长的长度
  • 队头下标:指向队头元素(出队位置)

  • 队尾下标:指向下一个插入位置

而在方法上,除了继承下来的方法,我们需要增加一些顺序结构的必要方法:

  • 队尾到达数组最大值的动作:

    • 当队列满时,扩充队列;
    • 当队列不满时,整体移动元素到从数组起始位置开始
  • 队列是否满

所以,我们建立一个新的头文件SequentialQueue.h来写顺序结构,并将顺序栈命名为SequentialQueue

即,我们的最终结构为:

#pragma once

#include "Queues.h"

namespace Queues
{
    template<typename T>
    class SequentialQueue : virtual public AbstractQueue<T>
    {
        public: // Constructor
        SequentialQueue();
        virtual ~SequentialQueue() override;

        protected: // protected Fields
        T* m_Items;         // 元素数组
        int m_FrontIndex;   // 队头下标
        int m_RearIndex;    // 队尾下标
        int m_MaxCount;     // 元素数组长度
        int m_Increament;   // 元素数组增长长度

        public: // public Properties
        inline virtual int GetCount() override;
        inline virtual int GetMaxCount();
        inline int GetIncreament();
        inline void PutIncreament(int value);

        __declspec(property(get = GetCount)) int count;
        __declspec(property(get = GetMaxCount)) int maxCount;
        __declspec(property(get = GetIncreament, put = PutIncreament)) int increament;

        protected: // protected Methods
        // 扩充队列。
        // 如果队列满了,或余量 < 增长率,则每次扩充`m_Increament`的长度。
        // 如果队列不满,且余量 >= 增长率,则将元素重置成从0开始
        virtual void Overflow(); 

        public: // public Methods
        virtual void Enqueue(T item) override;
        virtual T Dequeue() override;
        virtual T Front() override;
        virtual void Clear() override;
        virtual bool Empty() override;
        virtual bool Full(); // 队列是否满
    };
}
3.2.1 初始化与销毁(Initialize and Destroy)

在构造函数,我们主要是进行数组的初始化:

    template<typename T>
    inline SequentialQueue<T>::SequentialQueue()
    {
        m_FrontIndex = 0;
        m_RearIndex = 0;
        m_MaxCount = DEFAULT_MAX_COUNT;
        m_Increament = DEFAULT_INCREAMENT;

        m_Items = new T[m_MaxCount];
        if (m_Items == 0)
        {
            throw std::bad_alloc(); // 分配内存失败
        }
    }

类似的,在析构函数中,我们主要是对数组的销毁:

    template<typename T>
    inline SequentialQueue<T>::~SequentialQueue()
    {
        if (m_Items != 0)
        {
            delete[] m_Items;
        }

        m_FrontIndex = 0;
        m_RearIndex = 0;
        m_MaxCount = 0;
        m_Increament = 0;
    }
3.2.2 属性方法(Properties)

在属性中,有一个计算元素个数的方法GetCount()

在数组型队列中,假设我们入队为abcdef的顺序:

步骤入队出队FrontRear队列内元素
Init00
1a0(a)1a…
2b0(a)2ab…
3cd0(a)4abcd…
4a1(b)4.bcd…
5bc3(d)4…d…
6ef3(d)6…def

可以看到,在队列中元素个数等于队尾下标减去队头下标

所以内部字段对外的属性方法:

    template<typename T>
    inline int SequentialQueue<T>::GetCount()
    {
        return m_RearIndex - m_FrontIndex;
    }

    template<typename T>
    inline int SequentialQueue<T>::GetMaxCount()
    {
        return m_MaxCount;
    }

    template<typename T>
    inline int SequentialQueue<T>::GetIncreament()
    {
        return m_Increament;
    }

    template<typename T>
    inline void SequentialQueue<T>::PutIncreament(int value)
    {
        if (value < 1) // 对立的增长率不能小于1
        {
            value = 1;
        }
        m_Increament = value;
    }
3.2.3 主要方法(Main Methods)

我们逐个添加,要注意每个方法的前置条件

  • 入队(Enqueue):要注意顺序,这里在初始化和入队都采用的是先入队后移下标(下同)。如果你需要先移下标后入队,还需更改初始化等方法。

        template<typename T>
        void SequentialQueue<T>::Enqueue(T item)
        {
            if (m_RearIndex == m_MaxCount) // 如果队尾达到最大值
            {
                Overflow(); // 整体移动或者扩充队列
            }
            m_Items[m_RearIndex] = item; // 入队
            m_RearIndex++; // 下标+1(后移)
        }
    
  • 出队(Dequeue):出队之后要判断是否为空,重置下标后可稍微有效的利用空间

        template<typename T>
        T SequentialQueue<T>::Dequeue()
        {
            if (Empty()) // 如果队列空
            {
                throw std::out_of_range("no element."); // 溢出错误
            }
            
            T item = m_Items[m_FrontIndex]; // 取出元素
            m_Items[m_FrontIndex] = 0; // 将此位置设置为空
            m_FrontIndex++; // 队头位置+1(后移)
    
            if (Empty()) // 如果队列空
            {
                m_FrontIndex = 0; // 重置队头下标
                m_RearIndex = 0; // 重置队尾下标
            }
    
            return item; // 返回取出的元素
        }
    
  • 获取队头元素(Front):

        template<typename T>
        T SequentialQueue<T>::Front()
        {
            if (Empty()) // 如果队列空
            {
                throw std::out_of_range("no element."); // 溢出错误
            }
            return m_Items[m_FrontIndex];
        }
    
  • 清空队列(Clear):

        template<typename T>
        void SequentialQueue<T>::Clear()
        {
            // 循环清空
            for (int i = m_FrontIndex; i < m_RearIndex; i++)
            {
                m_Items[i] = 0;
            }
            m_FrontIndex = 0; // 重置队头
            m_RearIndex = 0; // 重置队尾
        }
    
  • 判断队列是否为空(Empty):

        template<typename T>
        bool SequentialQueue<T>::Empty()
        {
            return count == 0;
        }
    
  • 判断队列是否为满(Full):

        template<typename T>
        bool SequentialQueue<T>::Full()
        {
            return count == maxCount;
        }
    
  • 队尾溢出处理(Overflow):

        template<typename T>
        void SequentialQueue<T>::Overflow()
        {
            if (Full() || m_FrontIndex < m_Increament) // 如果队列满了,或余量 < 增长率
            {
                int newSize = m_MaxCount + m_Increament; // 新的长度 = 旧长度 + 增长率
                T* items = new T[newSize]; // 用新的长度初始化新的元素数组
                if (items == 0)
                {
                    throw std::bad_alloc(); // 分配内存失败
                }
    
                // 将旧数组中的元素复制到新数组
                for (int i = 0; i < m_MaxCount; i++)
                {
                    items[i] = m_Items[i];
                }
    
                delete[] m_Items; // 删除旧数组
                m_Items = items; // 将新数组赋值
                m_MaxCount = newSize; // 更新长度
            }
            else // 如果队列没有满,且余量 >= 增长率
            {
                int length = count; // 保存当前数组长度
                // 按从队头到队尾的顺序,整体移动到从0开始
                for (int i = m_FrontIndex, j = 0; i < m_RearIndex; i++, j++)
                {
                    m_Items[j] = m_Items[i];
                    m_Items[i] = 0;
                }
    
                m_FrontIndex = 0; // 重新设定队头下标
                m_RearIndex = length; // 重新设定队尾下标
            }
        }
    

3.3 循环队列(Circular Queue)

循环队列是为了处理数组队列的“假溢出”现象,它首尾相接形成一个环。

可以用数组也可以用链表来表示。我们这里还是使用数组。

在前进过程中,当队头或队尾超过最大值时,它重新回到零位继续前进,即:

  • 当队头超过数组最大空间时,队头重新回到0;

  • 当队尾超过数组最大空间时,队尾重新回到0。

而在入队和出队时,它们前进的运算可以做判断或取模(%)

它大部分内容和数组队列一样,我们只需修改一部分即可。

即,我们的最终结构为:

#pragma once

#include "SequentialQueue.h"

namespace Queues
{
    template<typename T>
    class CircularQueue : public SequentialQueue<T>
    {
        public: // public Properties
        inline virtual int GetCount() override;
        inline virtual int GetMaxCount() override;

        __declspec(property(get = GetCount)) int count;
        __declspec(property(get = GetMaxCount)) int maxCount;

        protected: // protected Methods
        virtual void Overflow() override; // 以this->m_Increament扩充循环队列。

        public: // public Methods
        virtual void Enqueue(T item) override;
        virtual T Dequeue() override;
        virtual void Clear() override;
    };
}

Tips 关于队满条件
在数组队列中,我们的队满条件为count == maxCount,由于countmaxCount是我们封装的方法,所以只需要更改countmaxCount的方法就可以了,不用重写队满判断。
在循环队列中,队满条件也可以使用(m_RearIndex + 1) % m_MaxCount == m_FrontIndex,原理相同。

3.3.1 元素数量(Item Count)

循环队列中,由于队尾下标可以在队头下标前面,所以不能简单的使用m_RearIndex - m_FrontIndex,你要先判断其左右位置。

  • 当队头小于等于队尾时,元素数量等于队尾下标减去队头下标;

  • 当队头大于队尾时,元素数量等于最大容量减去队头下标加上队尾下标。

    • 右侧元素 = 最大容量 - 队头下标(下标是从0开始,但容量是从1开始)
    • 左侧元素 = 队尾下标(下标是从0开始,即是数量)

举例:

  • 假设有最大容量5的队列
    • 则元素位置为12345,对应下标为01234
    • 如果队头指向元素4,队尾指向元素2,则:
      右侧元素个数 = 最大容量5 - 元素位置4 + 1 = 最大容量5 - 队头下标3 = 2
      左侧元素个数 = 元素位置2 - 1 = 队尾下标1 = 1
      总数 = 2 + 1 = 3

代码即:

    template<typename T>
    inline int CircularQueue<T>::GetCount()
    {
        return (this->m_FrontIndex > this->m_RearIndex) 
            ? (this->m_MaxCount - this->m_FrontIndex + this->m_RearIndex) 
            : (this->m_RearIndex - this->m_FrontIndex);
    }

说完了元素数量,再来看看最大元素个数,这和数组队列的区别在于:队尾下标不能追到队头下标,即队头下标的前一个位置永远是空。这是由于如果最后一个位置入队了,那么队头就等于队尾,不要忘记,我们判断队列空就是用的队头等于队尾。

这也是我们需要重写的:

    template<typename T>
    inline int CircularQueue<T>::GetMaxCount()
    {
        return this->m_MaxCount - 1;
    }

注意1:m_MaxCount指数组长度,maxCount指数组内元素最大数量,使用哪一个要分析清楚(对于外部使用来说,可能只关心“我可以存多少数据?”)。

注意2:如果你觉得名字一样看起来很乱,你可以:不重写GetMaxCount()方法,而是添加一个新的对外属性变量来表示队内元素最大数量,然后重写Full()方法((m_RearIndex + 1) % m_MaxCount == m_FrontIndex)。

3.3.2 主要方法(Main Methods)

循环队列中,我们不用特别关注重置下标的问题。

而在进行下标递增时,要额外注意达到最大容量时的操作。你可以使用条件判断使它归零,也可以使用取模来计算。

  • 入队(Enqueue):

        template<typename T>
        void CircularQueue<T>::Enqueue(T item)
        {
            if (this->Full()) // 如果队满
            {
                Overflow(); // 扩充队列
            }
            this->m_Items[this->m_RearIndex] = item; // 入队
            this->m_RearIndex = (this->m_RearIndex + 1) % this->m_MaxCount; // 取模计算下标
        }
    
  • 出队(Dequeue):

        template<typename T>
        T CircularQueue<T>::Dequeue()
        {
            if (this->Empty()) // 如果队列空
            {
                throw std::out_of_range("no element."); // 溢出错误
            }
    
            T item = this->m_Items[this->m_FrontIndex]; // 取出元素
            this->m_Items[this->m_FrontIndex] = 0; // 将此位置设置为空
            this->m_FrontIndex = (this->m_FrontIndex + 1) % this->m_MaxCount; // 取模计算下标
    
            return item; // 返回取出的元素
        }
    
  • 清空队列(Clear):

        template<typename T>
        void CircularQueue<T>::Clear()
        {
            while (!this->Empty())
            {
                Dequeue();
            }
        }
    
  • 队满溢出处理(Overflow):在队满处理时,你同样要注意队头与队尾的位置

        template<typename T>
        void CircularQueue<T>::Overflow()
        {
            int newSize = this->m_MaxCount + this->m_Increament; // 新的长度 = 旧长度 + 增长率
            T* items = new T[newSize]; // 用新的长度初始化新的元素数组
            if (items == 0)
            {
                throw std::bad_alloc(); // 分配内存失败
            }
    
            // 将旧数组中的元素复制到新数组
            if (this->m_FrontIndex > this->m_RearIndex)
            {
                int newIndex = 0;
                
                // 先复制右侧数据
                for (int i = this->m_FrontIndex; i < this->m_MaxCount; i++)
                {
                    items[newIndex] = this->m_Items[i];
                    newIndex++;
                }
                // 再复制左侧数据
                for (int i = 0; i < this->m_RearIndex; i++)
                {
                    items[newIndex] = this->m_Items[i];
                    newIndex++;
                }
    
                this->m_FrontIndex = 0; // 重置队头下标
                this->m_RearIndex = newIndex; // 重置队尾下标
            }
            else // 在队头较小的情况下,队满只有一种情况,队头在0,队尾在this->m_MaxCount-1
            {
                for (int i = 0; i < this->m_RearIndex; i++)
                {
                    items[i] = this->m_Items[i];
                }
            }
    
            delete[] this->m_Items; // 删除旧数组
            this->m_Items = items; // 将新数组赋值
            this->m_MaxCount = newSize; // 更新长度
        }
    

3.4 链式队列(Linked Queue)

在链式结构中,链表用于存储数据

它同样需要一个队头和队尾,我们采用两个指针,队头有头节点的方式。

  • 插入时,在队尾,只更改队尾指针;

  • 删除时,在队头,只更改队头指针。

我们建立一个新的头文件LinkedQueue.h来写链式结构,并将链式队列命名为LinkedQueue

即,我们的链式队列最终为:

#pragma once

#include "Queues.h"

namespace Queues
{
    template<typename T>
    struct LinkedNode
    {
        T item;
        struct LinkedNode<T>* next;
    };

    template<typename T>
    class LinkedQueue : virtual public AbstractQueue<T>
    {
        public: // Constructor
        LinkedQueue();
        virtual ~LinkedQueue() override;

        protected: // protected Fields
        LinkedNode<T>* m_Front; // 队头
        LinkedNode<T>* m_Rear; // 队尾
        int m_Count;

        public: // public Properties
        inline virtual int GetCount() override;
        __declspec(property(get = GetCount)) int count;

        public: // public Methods
        virtual void Enqueue(T item) override;
        virtual T Dequeue() override;
        virtual T Front() override;
        virtual void Clear() override;
        virtual bool Empty() override;
    };

    template<typename T>
    inline int LinkedQueue<T>::GetCount()
    {
        return m_Count;
    }
}
3.4.1 初始化与销毁(Initialize and Destroy)

初始化与销毁的主要对象是链表的头节点

    template<typename T>
    inline LinkedQueue<T>::LinkedQueue()
    {
        m_Front = new LinkedNode<T>();
        if (m_Front == 0)
        {
            throw std::bad_alloc(); // 内存分配失败
        }
        m_Front->item = 0;
        m_Front->next = 0;

        m_Rear = m_Front;

        m_Count = 0;
    }

    template<typename T>
    inline LinkedQueue<T>::~LinkedQueue()
    {
        Clear();
        m_Rear = 0;
        delete m_Front;
    }
3.4.2 主要方法(Main Methods)

我们继续依次添加。

  • 入队(Enqueue):

        template<typename T>
        void LinkedQueue<T>::Enqueue(T item)
        {
            LinkedNode<T>* newRear = new LinkedNode<T>(); // 初始化新队尾
            if (newRear == 0)
            {
                throw std::bad_alloc(); // 分配内存失败
            }
            newRear->item = item;
            newRear->next = 0;
    
            m_Rear->next = newRear; //队尾插入
            m_Rear = newRear; // 设置新队尾
    
            m_Count++; // 数量+1
        }
    
  • 出队(Dequeue):

        template<typename T>
        T LinkedQueue<T>::Dequeue()
        {
            if (Empty()) // 如果队列空
            {
                throw std::underflow_error("no element."); // 溢出错误
            }
    
            LinkedNode<T>* oldFront = m_Front->next; // 取出当前队头,作为旧队头
            m_Front->next = oldFront->next; // 设置新队头
            oldFront->next = 0;
            T item = oldFront->item; // 取出队头数据
            delete oldFront; // 删除旧队头
            
            m_Count--; // 数量-1
            if (Empty()) // 如果队列空
            {
                m_Rear = m_Front; // 更新队尾
            }
            return item;
        }
    
  • 获取队头元素(Front):

        template<typename T>
        T LinkedQueue<T>::Front()
        {
            if (Empty()) // 如果队列空
            {
                throw std::underflow_error("no element."); // 溢出错误
            }
            return m_Front->next->item;
        }
    
  • 清空队列(Clear):

        template<typename T>
        void LinkedQueue<T>::Clear()
        {
            LinkedNode<T>* node;
            while (!Empty())
            {
                node = m_Front->next; // 取当前队头,作为旧队头
                m_Front->next = node->next; // 设置新队头
                node->next = 0;
                delete node; // 删除旧队头
            }
            m_Rear = m_Front;
            m_Count = 0;
        }
    
  • 判断队列是否空(Empty):

        template<typename T>
        bool LinkedQueue<T>::Empty()
        {
            return m_Front->next == 0; // 或者 count == 0;
        }
    

3.5 测试队列(Queue Testing)

到目前为止,我们完成了三种队列的编写,我们来稍微测试一下它们。

创建一个主函数main.cpp,内容如下:

#include <iostream>

#include "SequentialQueue.h"
#include "CircularQueue.h"
#include "LinkedQueue.h"

using namespace std;

int main()
{
    Queues::SequentialQueue<char> sQueue;
    Queues::CircularQueue<char> cQueue;
    Queues::LinkedQueue<char> lQueue;

    cout << "为每个队列添加[a, z]字母(Enqueue)" << endl;
    for (char ch = 'a'; ch <= 'z'; ch++)
    {
        sQueue.Enqueue(ch);
        cQueue.Enqueue(ch);
        lQueue.Enqueue(ch);
    }
    cout << "数组队列数量:" << sQueue.count << " / " << sQueue.maxCount << endl;
    cout << "循环队列数量:" << cQueue.count << " / " << cQueue.maxCount << endl;
    cout << "链式队列数量:" << lQueue.count << endl;
    cout << endl;

    cout << "出队打印(Dequeue):" << endl;
    // 打印结果应为:"aaa bbb .... zzz" (每10个字母换行)
    int i = 0;
    while (sQueue.count > 0)
    {
        cout << sQueue.Dequeue() << cQueue.Dequeue() << lQueue.Dequeue();
        cout << ", ";
        if (++i % 10 == 0)
        {
            cout << endl;
        }
    }
    cout << endl;
    cout << "数组队列数量:" << sQueue.count << " / " << sQueue.maxCount << endl;
    cout << "循环队列数量:" << cQueue.count << " / " << cQueue.maxCount << endl;
    cout << "链式队列数量:" << lQueue.count << endl;
    cout << endl;

    cout << "数组队列增长率16,先入26个,再退25个,当前front=25, rear=26" << endl;
    cout << "再进入230个元素,此时队尾到达最大值,但余量是25。" << endl;
    cout << "此时将整体移动数组队列位置(Overflow)" << endl;
    for (int i = 0; i < 26; i++)
    {
        sQueue.Enqueue('a');
        if (i != 0)
        {
            sQueue.Dequeue();
        }
    }
    for (int i = 0; i < 230; i++)
    {
        sQueue.Enqueue('a');
    }
    cout << "数组队列数量:" << sQueue.count << " / " << sQueue.maxCount << endl;
    cout << endl;

    cout << "进入26个元素,此时将扩充数组队列(Overflow)" << endl;
    for (int i = 0; i < 26; i++)
    {
        sQueue.Enqueue('a');
    }
    cout << "数组队列数量:" << sQueue.count << " / " << sQueue.maxCount << endl;
    cout << endl;

    cout << "清除数组队列(CLEAR)" << endl;
    sQueue.Clear();
    cout << "数组队列数量:" << sQueue.count << " / " << sQueue.maxCount << endl;
    cout << endl;

    system("pause");
    return 0;
}

输出结果为:

为每个队列添加[a, z]字母(Enqueue)
数组队列数量:26 / 255
循环队列数量:26 / 254
链式队列数量:26

出队打印(Dequeue):
aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj,
kkk, lll, mmm, nnn, ooo, ppp, qqq, rrr, sss, ttt,
uuu, vvv, www, xxx, yyy, zzz,
数组队列数量:0 / 255
循环队列数量:0 / 254
链式队列数量:0

数组队列增长率16,先入26个,再退25个,当前front=25, rear=26
再进入230个元素,此时队尾到达最大值,但余量是25。
此时将整体移动数组队列位置(Overflow)
数组队列数量:231 / 255

进入26个元素,此时将扩充数组队列(Overflow)
数组队列数量:257 / 271

清除数组队列(CLEAR)
数组队列数量:0 / 271

请按任意键继续. . .


4 队列的应用实例(Queue Examples)

实例使用内置的队列#include <queue>

当然,你也可以使用上述完成的队列,也可以使用自己编写的队列。

内置队列的区别:

  • Enqueue名称为push

  • Dequeue名称为pop,且没有返回值,获取队头只能用front

实例待补充,如果有补充将会在这里更新链接。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值