队列
队列是一种特殊的线性表,特殊在于队列只能在表头的一端出列,在表尾的一端入列,所以被称为先进先出
队列实现
队列可以由数组或者链表来实现
链表实现
通过链表实现的队列不需要提前指定队列大小,在出列的时候也能及时的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;
}
结果如下: