C语言实现循环队列

本文详细介绍了队列的两种主要实现方式——链表和数组,以及循环队列的原理和扩容策略,着重讨论了它们在内存管理上的优缺点。
摘要由CSDN通过智能技术生成

队列

队列是一种特殊的线性表,特殊在于队列只能在表头的一端出列,在表尾的一端入列,所以被称为先进先出

队列实现

队列可以由数组或者链表来实现

链表实现

通过链表实现的队列不需要提前指定队列大小,在出列的时候也能及时的free释放内存,但缺点在于修改的效率并不高
相关宏定义

#include <stdio.h>
#include <stdlib.h>
#define ElementType int

队列结构:

typedef struct Queue
{
    Node *front;
    Node *rear;
} Queue;

队列中每个节点的结构

typedef struct Node
{
    ElementType data;
    struct Node *next;
} Node;

createQueue函数会创建一个队列并返回

Queue *createQueue()
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->next = NULL;
    Queue *queue = (Queue *)malloc(sizeof(Queue));
    queue->front = node;
    queue->rear = node;
    return queue;
}

appendQueue函数会向指定队列放入一个新节点,
参数1:指定的值
参数二:指定的队列

void appendQueue(ElementType value, Queue *q)
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = value;
    q->rear->next = node;
    q->rear = q->rear->next;
}

dequeue函数用于将指定队列出列

void dequeue(Queue *q)
{
    if (q->front == q->rear)
    {
        printf("队列为空\n");
        return;
    }
    Node *node = q->front;
    q->front = node->next;
    if (node == q->rear)
    {
        q->rear = q->front;
    }
    free(node);
}

printQueue函数用于打印指定的队列
参数1:指定的队列

void printQueue(Queue *q)
{
    if (q->front == q->rear)
    {
        printf("队列为空\n");
        return;
    }
    Node *head = q->front->next;
    while (head != q->rear->next)
    {
        printf("%d ", head->data);
        head = head->next;
    }
    printf("\n");
}

测试代码:

int main()
{
    Queue *queue = createQueue();
    appendQueue(1, queue);
    appendQueue(2, queue);
    printQueue(queue);
    dequeue(queue);
    printQueue(queue);
    dequeue(queue);
    printQueue(queue);
    dequeue(queue);
    return 0;
}

结果如下
结果

数组实现

相较于使用链表实现,通过数组实现的队列容量是固定的,在容量到达上限时必须经过扩容步骤才能继续存储,另外被出列的元素也无法像链表队列里出列的元素一样被free释放
但与链表队列不同的是,数组队列有着链表队列无法比拟的修改效率
相关宏定义:

#include <stdio.h>
#include <stdlib.h>
#define ElementType int
#define MAXSIZE 100
#define SIZE 5

队列结构:

typedef struct Queue
{
    ElementType *data;
    ElementType front;
    ElementType rear;
    int size;
} Queue;

createQueue函数用于创建一个队列并返回
参数1:队列的初始容量

Queue *createQueue(int size)
{
    Queue *queue = (Queue *)malloc(sizeof(Queue));
    queue->front = 0;
    queue->rear = 0;
    queue->data = (ElementType *)malloc(sizeof(ElementType) * size);
    queue->size = size;
    return queue;
}

appendQueue函数用于向指定队列中添加指定的元素,当容量不足时会自动扩容
参数1:指定的值
参数2:指定的队列

void appendQueue(ElementType value, Queue *q)
{
    if (q->rear == q->size)
    {
        if (q->size >= MAXSIZE)
        {
            printf("队列已扩容至最大值,无法扩容\n");
            return;
        }
        printf("内存不足,需扩容\n");
        expansionArray(q);
    }
    q->data[q->rear] = value;
    q->rear++;
}

expansionArray函数用来将指定队列中的数组扩容
参数1:需要被扩容的队列

void expansionArray(Queue *q)
{
    ElementType *data = q->data;
    data = (ElementType *)realloc(data, sizeof(data) * (q->size + SIZE));
    q->size += SIZE;
}

dequeue函数用于将指定队列中的元素出列
参数1:指定的队列

void dequeue(Queue *q)
{
    if (q->front == q->rear)
    {
        printf("队列为空\n");
        return;
    }
    q->front++;
}

printQueue函数用于打印指定的队列

void printQueue(Queue *q)
{
    if (q->front == q->rear)
    {
        printf("队列为空\n");
        return;
    }
    for (int i = q->front; i < q->rear; i++)
    {
        printf("%d ", q->data[i]);
    }
    printf(" front=%d,rear=%d\n", q->front, q->rear);
}

测试代码:

int main()
{
    Queue *queue = createQueue(5);
    appendQueue(1, queue);
    appendQueue(2, queue);
    appendQueue(3, queue);
    appendQueue(4, queue);
    appendQueue(5, queue);
    printQueue(queue);
    appendQueue(6, queue);
    printQueue(queue);
    dequeue(queue);
    printQueue(queue);
    return 0;
}

结果如下
结果

循环队列

通过数组实现的队列在元素出列后该元素的位置无法被使用
如下代码所示

int main()
{
    Queue *queue = createQueue(5);
    appendQueue(1, queue);
    appendQueue(2, queue);
    appendQueue(3, queue);
    appendQueue(4, queue);
    appendQueue(5, queue);
    printQueue(queue);
    dequeue(queue);
    printQueue(queue);
    appendQueue(6, queue);
    printQueue(queue);
    return 0;
}

结果
可以看到此时队列中只有4个元素,但在插入元素6的时候依旧提示了容量不足
这是因为我们的元素1虽然被出列了但其所在的位置却没有被使用
这种情况被称为假溢出

假溢出即当尾指针指向队列最末端时,插入元素将会失败,但此时的队列的存储空间并未全部占满

循环队列实现

因为只有通过数组实现的列表才会出现假溢出,所以循环队列我们通过数组实现
相关宏定义:

#include <stdio.h>
#include <stdlib.h>
#define ElementType int

队列结构:

typedef struct Queue
{
    ElementType *data;
    ElementType front;
    ElementType rear;
    int size;
} Queue;

createQueue函数用于创建一个队列并返回
参数1:队列的大小

Queue *createQueue(int size)
{
    Queue *queue = (Queue *)malloc(sizeof(Queue));
    queue->front = 0;
    queue->rear = 0;
    queue->data = (ElementType *)malloc(sizeof(ElementType) * size);
    queue->size = size;
    return queue;
}

appendQueue函数用于向指定队列中插入指定元素,如果容量超过预设值则不会扩容
参数1:指定元素
参数2:指定队列


void appendQueue(ElementType value, Queue *q)
{
    if ((q->rear == q->size && q->front == 0) || q->rear - q->front == q->size)
    {
        printf("内存不足,需扩容\n");
        return;
    }
    q->data[q->rear % q->size] = value;
    q->rear++;
}

dequeue函数用于将指定队列中的元素出列
参数1:指定的队列

void dequeue(Queue *q)
{
    if (q->front == q->rear)
    {
        printf("队列为空\n");
        return;
    }
    q->front++;
}

printQueue函数用于打印指定的队列
参数1:指定的队列

void printQueue(Queue *q)
{
    if (q->front == q->rear)
    {
        printf("队列为空\n");
        return;
    }
    int index = q->front % q->size;
    while (1)
    {
        if (index == q->rear)
        {
            break;
        }
        printf("%d ", q->data[index % q->size]);

        index++;
    }
    printf(" front=%d,rear=%d\n", q->front, q->rear);
}

测试代码:

int main()
{
    Queue *queue = createQueue(5);
    appendQueue(1, queue);
    appendQueue(2, queue);
    appendQueue(3, queue);
    appendQueue(4, queue);
    appendQueue(5, queue);
    printQueue(queue);
    dequeue(queue);
    printQueue(queue);
    appendQueue(6, queue);
    printQueue(queue);
    appendQueue(7, queue);
    printQueue(queue);
    return 0;
}

结果如下:
结果

循环队列的扩容

在循环队列实现之后我们的队列解决了假溢出的问题,但当队列空间真的被占满,遇到了真溢出的情况,我们想要队列自动扩容的话怎么解决呢
有两种解决方案,realloc和malloc

realloc

realloc会在数组原有基础上扩容,不需要对数组做进一步处理,但扩容后的列表顺序会有异常,我们需要手动调整
基于以上循环队列,相同部分的代码不再贴出
相关宏定义:

#include <stdio.h>
#include <stdlib.h>
#define ElementType int
#define MAXSIZE 100
#define SIZE 5

函数声明:

void depArray(Queue *);
void expansionArray(Queue *);
Queue *createQueue(int);
void appendQueue(ElementType, Queue *);
void dequeue(Queue *);
void printQueue(Queue *);

appendQueue函数会将指定的元素放入指定的队列中,当队列长度不足时队列会自动扩容
参数1:指定的值
参数2:指定的队列

void appendQueue(ElementType value, Queue *q)
{
    if ((q->rear == q->size && q->front == 0) || q->rear - q->front == q->size)
    {
        printf("内存不足,需扩容\n");
        expansionArray(q);
    }
    q->data[q->rear % q->size] = value;
    q->rear++;
}

expansionArray函数会将指定的队列扩容
参数1:指定的队列

void expansionArray(Queue *q)
{
    ElementType *data = q->data;
    data = (ElementType *)realloc(data, sizeof(data) * (q->size + SIZE));
    q->size += SIZE;
    depArray(q);
}

depArray函数用于将整理指定队列的顺序

void depArray(Queue *q)
{
    int index = 0;
    for (int i = 0; i < q->front % q->size && i < SIZE; i++, index = i)
    {
        q->data[q->size - SIZE + i] = q->data[i];
    }
    for (int i = 0; i < q->front - index; i++)
    {
        q->data[i] = q->data[index + i];
    }
}

测试代码:

int main()
{
    Queue *queue = createQueue(5);
    appendQueue(1, queue);
    appendQueue(2, queue);
    appendQueue(3, queue);
    appendQueue(4, queue);
    appendQueue(5, queue);
    printQueue(queue);
    dequeue(queue);
    appendQueue(6, queue);
    appendQueue(7, queue);
    printQueue(queue);
    dequeue(queue);
    dequeue(queue);
    dequeue(queue);
    dequeue(queue);
    dequeue(queue);
    printQueue(queue);
    appendQueue(8, queue);
    appendQueue(9, queue);
    appendQueue(10, queue);
    appendQueue(11, queue);
    appendQueue(12, queue);
    appendQueue(13, queue);
    appendQueue(14, queue);
    appendQueue(15, queue);
    appendQueue(16, queue);
    printQueue(queue);
    appendQueue(17, queue);
    printQueue(queue);
    return 0;
}

结果

malloc

malloc不会修改原有数组,而是另开辟一块内存空间,当内存空间不足时可能会开辟失败
基于以上循环队列,相同部分的代码不再贴出
相关宏定义:

#include <stdio.h>
#include <stdlib.h>
#define ElementType int
#define MAXSIZE 100
#define SIZE 5

函数声明:

void expansionArray(Queue *);
Queue *createQueue(int);
void appendQueue(ElementType, Queue *);
void dequeue(Queue *);
void printQueue(Queue *);

appendQueue函数会将指定的元素放入指定的队列中,当队列长度不足时队列会自动扩容
参数1:指定的值
参数2:指定的队列

void appendQueue(ElementType value, Queue *q)
{
    if ((q->rear == q->size && q->front == 0) || q->rear - q->front == q->size)
    {
        printf("内存不足,需扩容\n");
        expansionArray(q);
    }
    q->data[q->rear % q->size] = value;
    q->rear++;
}

expansionArray函数会将指定的队列扩容
参数1:指定的队列

void expansionArray(Queue *q)
{
    ElementType *data = (ElementType *)malloc(sizeof(data) * (q->size + 5));
    q->size += 5;
    int j = 0;
    int index = q->front % q->size;
    while (1)
    {
        if (index == q->rear)
        {
            break;
        }
        data[j++] = q->data[index % (q->size - 5)];

        index++;
    }
    q->data = data;
    q->front = 0;
    q->rear = j;
}

测试代码:

int main()
{
    Queue *queue = createQueue(5);
    appendQueue(1, queue);
    appendQueue(2, queue);
    appendQueue(3, queue);
    appendQueue(4, queue);
    appendQueue(5, queue);
    printQueue(queue);
    dequeue(queue);
    appendQueue(6, queue);
    appendQueue(7, queue);
    printQueue(queue);
    dequeue(queue);
    dequeue(queue);
    dequeue(queue);
    dequeue(queue);
    dequeue(queue);
    printQueue(queue);
    appendQueue(8, queue);
    appendQueue(9, queue);
    appendQueue(10, queue);
    appendQueue(11, queue);
    appendQueue(12, queue);
    appendQueue(13, queue);
    appendQueue(14, queue);
    appendQueue(15, queue);
    appendQueue(16, queue);
    printQueue(queue);
    appendQueue(17, queue);
    printQueue(queue);
    return 0;
}

结果如下:
结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值