数据结构学习之循环队列(C数组实现)

循环队列(C数组实现)

总纲

  1. 队列的声明
  2. 队列的初始化
  3. 判断队列是否为空
  4. 入队
  5. 出队
  6. 获取队首元素
  7. 获取队尾元素
  8. 获取队列大小
  9. 打印队列
  10. 队列的销毁

注意: 这里的队列是循环的,如果满的话再加入元素会把前面的元素挤出去,也就是可以一直加入元素


一. 队列的声明

因为元素类型未知,所以用变量代替
一个队列结构体要具有队列容量,大小,数组的地址,首尾的索引

typedef int type;
typedef struct Cursionque
{
    type* arr;
    int front;
    int rear;
    int capacity;
    int size;
}queue;

二. 队列的初始化

首先想一想队列初始的状态是什么

  1. 容量一定,大小为0
  2. 这里的队列是循环队列,更像是一个圈。所以front和rear都置为-1
void init(queue* que, int cap)
{
    type* tmp = (type*)malloc(sizeof(type) * cap);
    if (tmp == NULL)
    {
        printf("MallocError\n");
        return;
    }
    else
    {
        que->arr = tmp;
        que->capacity = cap;
        que->front = que->rear = -1;
        que->size = 0;
    }
}

三. 判读队列是否为空

首位元素索引最好都判断一下

// 判断队列是否为空
bool ifEmpty(queue* que)
{
    return (que->front == -1) && (que->rear == -1);
}

四. 入队

首先要判断队列是否为空
另外一个要注意的点是front的变化,因为是循环队列,所以front的变化也要是循环的,所以要模上capacity,这样的话当front到capacity-1(数据这时候已经满了)时,再次入队front就变成0了

// 入队
void Enque(queue* que, type x)
{
    if (isEmpty(que))
    {
        que->rear++;
        que->front++;
    }
    else
    {
        que->front = (que->front + 1 ) % (que->capacity);
    }
    que->arr[que->front] = x;
    if (que->size != que->capacity)
    {
        que->size++;
    }
}

五. 出队

出队也要判断为空的情况,也要判断元素个数是不是为1的情况,因为这时候要同时移动front和rear
因为是循环队列,rear也要模上capacity

// 出队
void Deque(queue* que)
{
    if (isEmpty(que))
    {
        printf("AlreadyEmpty\n");
        return;
    }
    else if (que->front == que->rear)
    {
        que->front = -1, que->rear = -1;
    }
    else
    {
        que->rear = (que->rear + 1) % (que->capacity);
    }
    que->size--;
}

六. 获取队首元素

这个倒没什么需要特别注意的

// 获取队首元素
type Front(queue* que)
{
    if (isEmpty(que))
    {
        exit(1);
    }
    else
    {
        return que->arr[que->front];
    }
}

七. 获取队尾元素

这个也没什么特别需要注意的

// 获取队尾元素
type Rear(queue* que)
{
    if (isEmpty(que))
    {
        exit(1);
    }
    else
    {
        return que->arr[que->rear];
    }
}

八. 获取队列大小

// 获取队列大小
int sz(queue* que)
{
    return que->size;
}

九. 打印队列

首先需要判空

if (isEmpty(que))
    {
        printf("AlreadyEmpty\n");
        return;
    }

这里是循环队列,由于之前对front和rear的设置所以可能出现front小于rear的情况,而且我们是要从队首打印到队尾,这时可以利用size作为循环的条件

// 打印队列
void print(queue* que)
{
    // 由于是循环队列所以可能出现front小于rear的情况, 所以要特判一下
    if (isEmpty(que))
    {
        printf("AlreadyEmpty\n");
        return;
    }
    // 注意这里是从队首打印到队尾
    // 由于是循环队列所以可能出现front小于rear的情况, 所以要特判一下
    for (int i = 0; i < que->size; i++)
    {
        int j = (que->front - i + que->capacity) % (que->capacity);
        printf("%d ", que->arr[j]);
    }
}

有size个元素,就打印size次就好了
如果front大于rear,就减去i就好了
如果front小于rear呢,减去i可能会变成负数怎么办(如果C语言支持负数索引这个就没什么问题了) ————可以加上capacity再模上capacity(这样就是物理上从数组头部的位置移动到了尾部位置,逻辑上仍然是一个循环数组)


十. 队列的销毁

释放申请的空间,指针置空,全部置为初始状态

// 队列的销毁
void destroy(queue* que)
{
    free(que->arr);
    que->arr = NULL;
    que->capacity = 0;
    que->size = 0;
    que->rear = -1;
    que->front = -1;
}

测试

int main()
{
    queue test;
    init(&test, 5);
    for (int i = 0; i < 5; i++)
    {
        Enque(&test, i + 1);
        printf("sz = %d, cap = %d", test.size, test.capacity);
        printf("\n");
        print(&test);
        printf("\n");
        printf("front = %d, rear = %d\n", test.front, test.rear);
    }
    for (int i = 0; i < 3; i++)
    {
        Deque(&test);
        printf("sz = %d, cap = %d", test.size, test.capacity);
        printf("\n");
        print(&test);
        printf("\n");
        printf("front = %d, rear = %d\n", test.front, test.rear);
    }
    for (int i = 0; i < 8; i++)
    {
        Enque(&test, i * 2);
        printf("sz = %d, cap = %d", test.size, test.capacity);
        printf("\n");
        print(&test);
        printf("\n");
        printf("front = %d, rear = %d\n", test.front, test.rear);
    }
    return 0;
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值