循环队列的基本算法
一、介绍
正是因为队列从队头删除,从队尾添加的特点,所以在使用数组来表现队列时,元素的位置移动采用下标也即出队front++或者入队rear++的方式实现,这里会体现出一个局限性,资源空间的浪费。怎么理解呢?
草图所示:
图示解释:
一个数组队列是满的,arr[0]=a1 ,arr[1]=a2,arr[2]=a3,arr[3]=a4, 此时再将a5入队列肯定是失败的。那么可以依次将a1,a2出队列,此时可以看到arr[0],arr[1]的位置空出来了。然而,由于入队的元素必须从队尾进入,所以虽然有空余的位置arr[0],arr[1], a5却不能入队列,这就造成了空间的浪费。在这里可以做一个优化,不再单纯的将位置移动也即front++或者rear++,而是采用一个简单的算法来计算元素应该在数组中放置的位置,其实就是采用循环队列来解决这个问题。循环队列需要注意队列已满的判决条件,由于尾指针始终指向尾元素的下一个位置,所以队列始终会有一个空位置,其实未满,但是这种情况代表了已满。
草图所示:
循环队列算法
出队列:front = (front + 1) % maxSize
入队列:rear = (rear + 1) % maxSize
空队列:front == rear
满队列:front == (rear + 1) % maxSize
元素数:eleCount = (rear - front + maxSize) % maxSize
二、算法
#define MAXQSIZE 5 ///队列的最大长度 #define QUEUE_OVERFLOW -1 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int QElemType; typedef int Status; /// ----- 循环队列 ------- 队列的顺序存储结构 typedef struct { QElemType *base; //初始化的动态分配存储空间,存储元素 int front; //队头指针,若队列不空,指向队列头元素 int rear; //队尾指针,若队列不空,指向队列尾元素的下一个位置 }SqQueue; Status InitQueue(SqQueue &Q); //初始化一个空的循环队列 int QueueLength(SqQueue Q); //获取队元素个数 Status EnQueue(SqQueue &Q, QElemType e); //把元素e从队尾添加队列中 Status DeQueue(SqQueue &Q, QElemType &e); //获取队列的头元素,并取出元素值赋给e保存
三、代码
Status InitQueue(SqQueue &Q) { ///初始化一个空的循环队列 Q.base = (QElemType *)malloc(MAXQSIZE * sizeof(QElemType)); if (!Q.base) exit(QUEUE_OVERFLOW); //存储分配失败 Q.front = Q.rear = 0; cout<<"空队列创建成功"<<endl; return OK; } int QueueLength(SqQueue Q) { ///获取队元素个数 int eleCount = (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE; cout<<"队列元素有:"<<eleCount<<"个"<<endl; return eleCount; } Status EnQueue(SqQueue &Q, QElemType e){ ///把元素e从队尾添加队列中 if ((Q.rear + 1) % MAXQSIZE == Q.front) { cout<<"队列已满"<<endl; return ERROR; //队列已满 } Q.base[Q.rear] = e; Q.rear = (Q.rear + 1) % MAXQSIZE; cout<<"入队的元素:"<<e<<",front = "<<Q.front<<",rear = "<<Q.rear<<endl; return OK; } Status DeQueue(SqQueue &Q, QElemType &e){ ///获取队列的头元素,并取出元素值赋给e保存 if(Q.front == Q.rear){ cout<<"队列已空"<<endl; return ERROR; //队列已空 } e = Q.base[Q.front]; Q.front = (Q.front + 1) % MAXQSIZE; cout<<"出队的元素:"<<e<<",front = "<<Q.front<<",rear = "<<Q.rear<<endl; return OK; }
四、结果
测试:
int main() { //构建队列 SqQueue Q; if (InitQueue(Q)) { for (int i = 0; i < MAXQSIZE; ++i) { //入队列 EnQueue(Q, i + 1); } } //获取队列元素个数 QueueLength(Q); cout<<endl; for (int j = 0; j < 3; ++j) { //出队列 QElemType e; DeQueue(Q, e); //获取队列元素个数 QueueLength(Q); } return 0; }
打印:
/Users/xiayuanquan/CLionProjects/cycleQueue/cmake-build-debug/cycleQueue 空队列创建成功 入队的元素:1,front = 0,rear = 1 入队的元素:2,front = 0,rear = 2 入队的元素:3,front = 0,rear = 3 入队的元素:4,front = 0,rear = 4 队列已满 队列元素有:4个 出队的元素:1,front = 1,rear = 4 队列元素有:3个 出队的元素:2,front = 2,rear = 4 队列元素有:2个 出队的元素:3,front = 3,rear = 4 队列元素有:1个 进程已结束,退出代码 0
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!