数据结构之循环队列

队列

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

二是指针从头部往后移,依次取出所有元素,这种方式会导致取出元素的位置空了但是不能继续往里面放,即尾部已满但头部还是空的,这样会浪费空间。
在这里插入图片描述

循环队列

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

接下来时循环队列的实现,先创建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): =========================

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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
顺序循环队列是一种使用顺序存储结构实现的队列。它通过将队列的首尾相连,构成一个循环的结构,解决了普通队列在出队操作时需要移动元素的问题,提高了算法效率。[2] 顺序循环队列的结构定义如下: ```c #define SIZE 8 typedef struct Queue { int elem[SIZE]; // 存放队列元素 int front; // 队头 int rear; // 队尾 } Queue, *QueueS; ``` 其中,`elem`数组用于存放队列元素,`front`表示队头的位置,`rear`表示队尾的位置。当队列为空时,`front`和`rear`的值相等;当队列满时,`rear`的下一个位置就是`front`。通过这种方式,可以实现循环利用队列的存储空间。 顺序循环队列的操作包括入队和出队操作。入队操作将元素插入到队尾,同时更新`rear`的位置;出队操作将队头元素删除,同时更新`front`的位置。当队列满时,无法进行入队操作;当队列为空时,无法进行出队操作。因此,需要额外的判断条件来判断队列是否满或为空。 顺序循环队列的实现可以通过取模运算来实现循环的效果,即在计算`rear`和`front`的位置时,使用`(rear + 1) % SIZE`和`(front + 1) % SIZE`来计算新的位置。 总结来说,顺序循环队列是一种通过循环利用队列存储空间来提高算法效率的数据结构。它使用顺序存储结构实现,通过将队列的首尾相连构成循环结构,解决了普通队列在出队操作时需要移动元素的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值