队列的实现(1):循环队列的实现

队列是一种“先进先出的数据结构”,可分为静态队列和链式队列。静态队列一般使用数组实现,数组需要预先定义内存大小,为了避免内存浪费,一般使用循环队列。接下来讲述循环队列的原理以及实现代码。

循环队列数据结构定义:
int front;//指向队列头,指向第一个数据节点
int rear;//指向队列尾(并不是指向最后一个数据节点,而是最后一个数据节点后面的位置)
char data[];//节点数据,根据实际需要可以是不同的数据类型,但是因为是数组,需要在声明时指定大小

循环队列操作方法:

void circQue_Init(circQue_t* queue);`//初始化data数组的数据,front和rear设为0
void circQue_Deinit(circQue_t* queue);//销毁队列
bool isQueEmpty(circQue_t* queue);//检查队列是否为空,在获取队列最前面的数据前需要检查队列是否为空,判断依据是front是否和rear相等(不一定都是0)
bool isQueFull(circQue_t* queue);//检查队列是否已满,在往队列插入新的节点前需要检查队列是否已经满,判断依据是(rear+1)%dataLen == front,因为rear永远指向最后一个节点后面的位置,也就是说数组大小虽然是dataLen,但是实际最多只能存储dataLen-1个节点
bool circQue_add(circQue_t* queue, char newData);//往队列插入节点(即队列最后一个节点)
char circQue_remove(circQue_t* queue);//从队列移除节点(即队列第一个节点)
void printQueueData(circQue_t* queue);//打印队列数据

通常会比较疑惑的是,为什么rear不指向最后一个数据节点,而是指向最后一个节点后面的位置?
考虑这个情况:为什么我们要用(rear+1)%dataLen == front作为队列满的条件?因为如果使用rear==front作为判断条件,那么就和队列空的判断条件重复了,无法知道到底是满还是空。因此需要预留一个空间,当rear的后一个位置是front,说明队列已经满了。

队列满的情况:

还有一个容易犯的错误,循环队列的遍历。简单的数组或者单链表的遍历,都是从首位置开始,然后每次++,但是循环队列存在这样的情况:rear比front小,这个时候如果从front开始,每次自增1直到等于rear,条件将永远不成立。
举个例子,一个最多可存储5个元素的循环队列

插入三个节点,此时:
front为0,rear为3
将两个节点移除出队列,此时:
front为2,rear为3
插入三个节点,此时:
front为2,rear为1

可以看到,这就是循环队列的特点,rear的值已经比front小了

因此,采用下面的循环遍历队列:

for(int i = queue->front; i != queue->rear; i=(i+1)%MAX_NODE_NUM)

i = queue->front; while(i% MAX_NODE_NUM!= queue ->rear){…;i++}

以下是实现循环队列的源码:

#include <string.h>
#include <malloc.h>
#include <iostream>

#define MAX_NODE_NUM 10

using namespace std;

typedef struct circQueue{
    int front;
    int rear;
    char data[MAX_NODE_NUM];
}circQue_t; 

void circQue_Init(circQue_t* queue){        
    queue->front = 0;
    queue->rear = 0;
    memset(queue->data, 0, MAX_NODE_NUM);
}

void circQue_Deinit(circQue_t* queue){
    if(queue){
        cout << "will free queue,front is:" << queue->front <<",rear is:" << queue->rear << endl;
        free(queue);
    }
}

bool isQueEmpty(circQue_t* queue){
    return (queue->front == queue->rear);//when front equal rear means circular queque is empty
}

bool isQueFull(circQue_t* queue){
    return (((queue->rear + 1) % MAX_NODE_NUM == queue->front));//get the value of rear plus 1, then mod capacity of circular queue, queue is full if the result of mod is equal front  
}

bool circQue_add(circQue_t* queue, char newData){
    if(isQueFull(queue)){
        cout << "queue is full, add node failed!" << endl;  
        return false;   
    }
    queue->data[queue->rear] = newData;
    queue->rear = (queue->rear+1)%MAX_NODE_NUM;
    cout << "front is:" << queue->front << ",rear is:" << queue->rear << endl;
    return true;
}

char circQue_remove(circQue_t* queue){
    if(isQueEmpty(queue)){
        cout << "queue is empty, remove node failed!" << endl;  
        return 'x';         
    }
    char nodeValue = queue->data[queue->front];
    queue->front = (queue->front+1)%MAX_NODE_NUM;
    return  nodeValue;
}

void printQueueData(circQue_t* queue){
    for(int i = queue->front; i != queue->rear; i=(i+1)%MAX_NODE_NUM){
        cout << queue->data[i] << " ";
    }
    cout << endl;
}

int main(){
    circQue_t* que = (circQue_t*)malloc(sizeof(circQue_t));
    if(!que){
        cout << "malloc for circular queque failed!" << endl;
        return -1;  
    }   

    circQue_Init(que);

    circQue_add(que, 'a');
    circQue_add(que, 'b');
    circQue_add(que, 'c');
    printQueueData(que);
    circQue_remove( que);
    printQueueData(que);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值