也没想象中那么神秘的数据结构-先来后到的“队列”(循环队列)

概念

关于队列的相关内容,在之前的文章已经详细介绍过了,请参见《也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)》,本文主要将循环队列相关内容。

循环队列:在顺序队列中存在一种假溢出的现象,为了解决这种现象,将队列头尾相接,当后面的满了就从头开始,这种头尾相接的顺序存储结构我们称之为循环队列。

核心

队列的结构:队列包含front指向队头、rear指向队尾和size记录队列元素个数。

队列空的时候,front=rear,此时size=0。

队列满的时候,此时front和rear相隔一个,size=MAX_SIZE(最大长度)-1。之所以队列元素个数比最大个数少一个,是为了防止front和rear重合

入队:rear向后移一位,此时需要判断,若超出了最大长度,需要从0开始,可以使用rear=rear+1%MAX_SIZE

出队:front向后移一位,此时需要判断,若超出了最大长度,需要从0开始,可以使用front=front+1%MAX_SIZE

示例

★包含头文件queue_circular.h和源文件queue_circular.c(均已验证通过)。

 queue_circular.h

/**
 * @Filename : queue_circular.h
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(微信公众号:不只会拍照的程序猿)
 * @Description : 循环队列示例
**/
#ifndef __QUEUE_CIRCULAR_H__
#define __QUEUE_CIRCULAR_H__

#include <stdio.h>
#include <stdlib.h>


#define MAX_SIZE 10

/* 循环队列结构定义 */
struct t_queue{
    int buff[MAX_SIZE]; /* 保存队列元素 */
    int front;          /* 指向队头 */
    int rear;           /* 指向队尾 */
    int size;           /* 队列元素个数 */
};

/**
 * @初始化队列
 * @p_queue:队列
**/
void queue_init(struct t_queue *p_queue);

/**
 * @删除队列
 * @p_queue:队列
**/
void queue_deinit(struct t_queue *p_queue);

/**
 * @判断队列是否已满
 * @p_queue:队列
 * @返回1表示已满,0表示未满
**/
int queue_is_full(const struct t_queue *p_queue);

/**
 * @判断队列是否已空
 * @p_queue:队列
 * @返回1表示已空,0表示未空
**/
int queue_is_empty(const struct t_queue *p_queue);

/**
 * @获取队列元素个数
 * @p_queue:队列
 * @返回元素个数
**/
int queue_get_size(const struct t_queue *p_queue);

/**
 * @入队操作
 * @p_queue:队列    data:队列元素
 * @返回1表示成功,0表示失败
**/
int queue_push(struct t_queue *p_queue, int data);

/**
 * @出队操作
 * @p_queue:队列    data:队列元素
 * @返回1表示成功,0表示失败
**/
int queue_pop(struct t_queue *p_queue, int *p_data);

/**
 * @获取队头
 * @p_queue:队列    p_data:保存队头元素
 * @返回1表示成功,0表示失败
**/
int queue_get_front(const struct t_queue *p_queue, int *p_data);

/**
 * @打印队列元素
 * @p_queue:队列
**/
void queue_print(const struct t_queue *p_queue);

#endif

 queue_circular.c

/**
 * @Filename : queue_circular.c
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(微信公众号:不只会拍照的程序猿)
 * @Description : 循环队列示例
**/

#include "queue_circular.h"

/**
 * @初始化队列
 * @p_queue:队列
**/
void queue_init(struct t_queue *p_queue)
{
    p_queue->front = 0;
    p_queue->rear = 0;
    p_queue->size = 0;
}

/**
 * @删除队列
 * @p_queue:队列
**/
void queue_deinit(struct t_queue *p_queue)
{
    p_queue->front = 0;
    p_queue->rear = 0;
    p_queue->size = 0;
}

/**
 * @判断队列是否已满
 * @p_queue:队列
 * @返回1表示已满,0表示未满
**/
int queue_is_full(const struct t_queue *p_queue)
{
    return (p_queue->size >= MAX_SIZE - 1);
}

/**
 * @判断队列是否已空
 * @p_queue:队列
 * @返回1表示已空,0表示未空
**/
int queue_is_empty(const struct t_queue *p_queue)
{
    return (p_queue->size == 0);
}

/**
 * @获取队列元素个数
 * @p_queue:队列
 * @返回元素个数
**/
int queue_get_size(const struct t_queue *p_queue)
{
    return (p_queue->size);
}

/**
 * @入队操作
 * @p_queue:队列    data:队列元素
 * @返回1表示成功,0表示失败
**/
int queue_push(struct t_queue *p_queue, int data)
{
    // the queue is full, push failed
    if (queue_is_full(p_queue))
        return 0;

    p_queue->buff[p_queue->rear++] = data;
    p_queue->rear %= MAX_SIZE;
    p_queue->size++;

    return 1;
}

/**
 * @出队操作
 * @p_queue:队列    data:队列元素
 * @返回1表示成功,0表示失败
**/
int queue_pop(struct t_queue *p_queue, int *p_data)
{
    // the queue is empty, pop failed
    if (queue_is_empty(p_queue))
        return 0;

    *p_data = p_queue->buff[p_queue->front++];
    p_queue->front %= MAX_SIZE;
    p_queue->size--;

    return 1;
}

/**
 * @获取队头
 * @p_queue:队列    p_data:保存队头元素
 * @返回1表示成功,0表示失败
**/
int queue_get_front(const struct t_queue *p_queue, int *p_data)
{
    if (queue_is_empty(p_queue))
        return 0;

    *p_data = p_queue->buff[p_queue->front];

    return 1;
}

/**
 * @打印队列元素
 * @p_queue:队列
**/
void queue_print(const struct t_queue *p_queue)
{
    int i;

    for (i=0; i<p_queue->size; i++)
        printf("%d ", p_queue->buff[(i+p_queue->front)%MAX_SIZE]);

    printf("\n"); 
}

/**
 * @顺序队列测试代码
**/
int main(void)
{
    int data;
    struct t_queue my_queue;

    queue_init(&my_queue);      /* 初始化队列,此时为空队列 */   
    printf("the queue is %s\n", queue_is_empty(&my_queue) ? "empty" : "not empty");
    printf("---------------------------------------\n");

    /* 入队,队列:25 41 16 7 8 19 22,元素个数为7 */    
    queue_push(&my_queue, 25);
    queue_push(&my_queue, 41);
    queue_push(&my_queue, 16);
    queue_push(&my_queue, 7);
    queue_push(&my_queue, 8);
    queue_push(&my_queue, 19);
    queue_push(&my_queue, 22);   
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));
    queue_print(&my_queue);
    printf("---------------------------------------\n");

    /* 入队35 38 [11 22](队列已满,入队失败),队列:25 41 16 7 8 19 22 35 38,个数9 */
    queue_push(&my_queue, 35);
    queue_push(&my_queue, 38);
    queue_push(&my_queue, 11);
    queue_push(&my_queue, 22);
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));
    queue_print(&my_queue);
    printf("the queue is %s\n", queue_is_full(&my_queue) ? "full" : "not full");
    printf("---------------------------------------\n");

    /* 队头元素为25,第一次出队25,第二次出队41,队列:16 7 8 19 22 35 38,个数7 */
    if (queue_get_front(&my_queue, &data))
        printf("the front queue data is: %d\n", data);    
    if (queue_pop(&my_queue, &data))
        printf("the pop queue data is: %d\n", data);    
    if (queue_pop(&my_queue, &data))
        printf("the pop queue data is: %d\n", data);   
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));
    queue_print(&my_queue);
    printf("---------------------------------------\n");

    /* 清除队列,个数0 */
    queue_deinit(&my_queue);
    printf("the size of queue is: %d\n", queue_get_size(&my_queue));

    return 0;
}

结论

feng:queue$ gcc -o queue_circular queue_circular.c
feng:queue$ ./queue_circular
the queue is empty
---------------------------------------
the size of queue is: 7
25 41 16 7 8 19 22 
---------------------------------------
the size of queue is: 9
25 41 16 7 8 19 22 35 38 
the queue is full
---------------------------------------
the front queue data is: 25
the pop queue data is: 25
the pop queue data is: 41
the size of queue is: 7
16 7 8 19 22 35 38 
---------------------------------------
the size of queue is: 0
feng:queue$ 

本示例仅为循环队列示例,公众号也提供顺序栈示例《也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)》《也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)》以及队列的典型应用示例。

往期 · 推荐

也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)

也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)

也没想象中那么神秘的数据结构-后来居上的“栈”

我用C语言玩对象,观察者模式应用2-热水的用途

我用C语言玩对象,状态模式应用1-水的三态

关注

更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:数据结构源码,也可点击此处下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不只会拍照的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值