欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据结构之循环队列

程序员文章站 2022-06-06 20:52:52
...

队列

队列是一种先进先出的数据结构,就像排队买火车票,先去的人先买到票先走,后去的人就只能排在最后面,队列只允许在两端进行操作,即尾部插入元素,头部取走元素,普通队列处理元素有两种方式,一是头部元素依次出队,后面的元素跟着向前移动一位,当数据量非常大时这样效率比较低。
数据结构之循环队列

二是指针从头部往后移,依次取出所有元素,这种方式会导致取出元素的位置空了但是不能继续往里面放,即尾部已满但头部还是空的,这样会浪费空间。
数据结构之循环队列

循环队列

循环队列采用头指针尾指针循环移动,因为是循环的,尾指针可以一直向前移动,当头指针元素取出之后,在下一次添加元素时尾指针直接指向头指针的位置,避免上述情况二的浪费空间的问题,只要有空间,尾指针总是指向空出来的位置,循环队列另一个特点就是当没有元素和满元素时头指针和尾指针指向同一位置。
数据结构之循环队列

接下来时循环队列的实现,先创建MyQueue.h文件

/*
 *循环队列
 */
class MyQueue{
public:
    MyQueue(int dataCapacity);    //构造方法 参数:队列容量
    bool isQueueEmpty();          //判断队列是否为空
    void clearQueue();            //清空队列
    bool pushQueue(int element);  //入队 参数:放入队列的元素
    void  pullQueue(int *element);//出队
    bool isQueueFull();           //判断队列是否已满
    void queueTraverse();         //遍历队列
    int queueLength();            //当前队列长度
    ~MyQueue();                   //祈构函数
private:
    int m_iHead;                  //队头
    int m_iTail;                  //队尾
    int m_iQueueLength;           //队列当前元素个数
    int m_iDataCapacity;          //队列总容量大小
    int* m_iQueue;                //队列内部实现的数组
};

创建MyQueue.cpp文件,核心函数bool MyQueue::pushQueue(int element)和void MyQueue::pullQueue(int *element)

//
// Created by dongjiao.tang on 2019/11/23 0023.
//
#include "MyQueue.h"
#define TAG "dongjiao" //这个是自定义的LOG的标识
#include <android/log.h>
#include <cstdlib>

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
MyQueue::MyQueue(int dataCapacity) {
    m_iDataCapacity = dataCapacity;
    //初始化内部数组
    m_iQueue = new int[m_iDataCapacity];
    //初始化时清空队列
    clearQueue();
    m_iQueueLength = 0;
}
MyQueue::~MyQueue(){
     delete [] m_iQueue;
     m_iQueue = NULL;
}

bool MyQueue::isQueueEmpty() {
    return m_iQueueLength == 0;
}
void MyQueue::clearQueue() {
    m_iHead = 0;
    m_iTail = 0;
    m_iQueueLength = 0;
    LOGD("clearQueue........");
}
bool MyQueue::isQueueFull(){
    return m_iQueueLength == m_iDataCapacity;
}
//入队
bool MyQueue::pushQueue(int element) {
    LOGD("pushQueue...element = %d",element);
    if(isQueueFull()){
        LOGD("MyQueue isFull........element:%d can't pushQueue",element);
        return false;
    }else{
        //对m_iDataCapacity取余,保证m_iTail总是在0-m_iDataCapacity之间
        m_iTail = m_iTail%m_iDataCapacity;
        //将元素赋值给当前队尾所指向位置
        m_iQueue[m_iTail] = element;
        //如队之后对尾指针后移
        m_iTail++;
        m_iQueueLength++;
        return true;
    }
}
//出队
void MyQueue::pullQueue(int *element) {
    if(isQueueEmpty()){
        LOGD("MyQueue isEmpty.......element = NULL");
        *element = NULL;
    } else{
        //对m_iDataCapacity取余,保证m_iHead总是在0-m_iDataCapacity之间
        m_iHead = m_iHead%m_iDataCapacity;
        //取出对头元素
        *element = m_iQueue[m_iHead];
        //取出对头元素之后将此置空
        m_iQueue[m_iHead] = NULL;
        //出队之后对头指针后移
        m_iHead++;
        m_iQueueLength--;
        LOGD("pullQueue...element = %d",*element);
    }
}
void MyQueue::queueTraverse(){
    for (int i=m_iHead;i<m_iQueueLength+m_iHead;i++){
        //遍历队列,从对头开始,对m_iDataCapacity取余保证取出的元素在m_iQueue之中
        LOGD("queueTraverse element:%d",m_iQueue[i%m_iDataCapacity]);
    }
}
//队列当前元素的个数
int MyQueue::queueLength() {
    LOGD("current queueLength = :%d",m_iQueueLength);
    return m_iQueueLength;
}

最后来看Demo.cpp

void main(){
    int element;
    MyQueue *myQueue = new MyQueue(4);
    myQueue->pushQueue(10);
    myQueue->pushQueue(11);
    myQueue->pushQueue(12);
    LOGD("=========================");
    myQueue->queueTraverse();
    LOGD("=========================");
    myQueue->pullQueue(&element);
    myQueue->pullQueue(&element);
    LOGD("=========================");
    myQueue->queueTraverse();
    LOGD("=========================");
    myQueue->pushQueue(14);
    myQueue->pushQueue(15);
    myQueue->pushQueue(16);
    myQueue->pushQueue(17);
    LOGD("=========================");
    myQueue->queueTraverse();
    LOGD("=========================");
    for(int i=0;i<5;i++){
        myQueue->pullQueue(&element);
        myQueue->queueLength();
    }
    LOGD("=========================");
    myQueue->queueTraverse();
    delete myQueue;
    myQueue = NULL;
  }

附上log输出:

D/dongjiao( 6696): clearQueue........
D/dongjiao( 6696): pushQueue...element = 10
D/dongjiao( 6696): pushQueue...element = 11
D/dongjiao( 6696): pushQueue...element = 12
D/dongjiao( 6696): =========================
D/dongjiao( 6696): queueTraverse element:10
D/dongjiao( 6696): queueTraverse element:11
D/dongjiao( 6696): queueTraverse element:12
D/dongjiao( 6696): =========================
D/dongjiao( 6696): pullQueue...element = 10
D/dongjiao( 6696): pullQueue...element = 11
D/dongjiao( 6696): =========================
D/dongjiao( 6696): queueTraverse element:12
D/dongjiao( 6696): =========================
D/dongjiao( 6696): pushQueue...element = 14
D/dongjiao( 6696): pushQueue...element = 15
D/dongjiao( 6696): pushQueue...element = 16
D/dongjiao( 6696): pushQueue...element = 17
D/dongjiao( 6696): MyQueue isFull........element:17 can't pushQueue
D/dongjiao( 6696): =========================
D/dongjiao( 6696): queueTraverse element:12
D/dongjiao( 6696): queueTraverse element:14
D/dongjiao( 6696): queueTraverse element:15
D/dongjiao( 6696): queueTraverse element:16
D/dongjiao( 6696): =========================
D/dongjiao( 6696): pullQueue...element = 12
D/dongjiao( 6696): current queueLength = :3
D/dongjiao( 6696): pullQueue...element = 14
D/dongjiao( 6696): current queueLength = :2
D/dongjiao( 6696): pullQueue...element = 15
D/dongjiao( 6696): current queueLength = :1
D/dongjiao( 6696): pullQueue...element = 16
D/dongjiao( 6696): current queueLength = :0
D/dongjiao( 6696): MyQueue isEmpty.......element = NULL
D/dongjiao( 6696): current queueLength = :0
D/dongjiao( 6696): =========================

总的来说循环队列实现比较简单,需要想清楚尾指针和头指针的移动,入队时元素放在尾指针指向的位置,并且尾指针后移,出队时获取头指针指向的位置元素,并且头指针后移。

相关标签: 数据结构 C++