编程基础 - 队列 (Queue)

编程基础 - 队列 (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;
    }
<
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值