欢迎来到博主的专栏——C语言进阶指南
博主ID:代码小豪
文章目录
- 队列
- 顺序结构的队列
- 顺序队列的初始化
- 顺序队列的入队列操作
- 判断队列是否为空
- 顺序队列的出队列操作
- 顺序队列操作的所有代码
- 链式结构的队列
- 链式队列的初始化
- 链式队列的初始化
- 链式队列的入队列操作
- 链式队列的出队列的操作
- 链式队列的所有代码
队列
队列也是一种特殊的线性表,与栈先进后出(First In Last Out)的特性不同,队列的特性是先进先出(Firsr In First Out),即在表尾插入数据,在表头删除数据。
向队列插入数据的操作叫做入队列
向队列删除数据的操作叫做出队列
当数据出队列时,处于队头的元素被删除,队头的后继元素成为新的队头
当数据入队列时,将新数据插入队尾元素的后继元素,并将新数据成队尾
队列的物理存储结构可以分为两种:
一是顺序存储结构的队列,即以数组的形式实现的队列
二是链式存储结构的队列,即以链表的形式实现的队列
通常来说,链式存储结构的队列性能更好,适用性也更佳
顺序结构的队列
顺序结构的队列分为两种,一种是使用静态开辟的空间的队列,称为静态队列
静态队列的结构类型为:
#define MAXSIZE 10
typedef int QueueData;
typedef struct queue
{QueueData vals[MAXSIZE];int front;int rear;
};
静态队列的缺点很明显,那就是队列会出现满的情况,在这种情况下无法进行入队列的操作。
动态队列主要作用就是可以对队列进行扩容,当队列出现满队列的状况时,可以对队列进行操作。
动态队列的结构如下:
#define MAXSIZE 10
typedef int QueueData;
typedef struct queue
{QueueData* vals;int front;int rear;int capacity;
}queue;
顺序队列的初始化
将队列中的数据根据需要进行初始化。
void SeqQueueInit(queue* q1)
{q1->vals = NULL;q1->front = 0;q1->rear = 0;q1->capacity = 0;
}
顺序队列的入队列操作
将待入队的数据插入至队尾(rear)当中,并将队尾(rear)指向下一个待插入数据的空间位置
void SeqQueuePush(queue* q1, QueueData e)
{if (SeqQueueFull(q1))//判断队列是否满{//满则进行扩容int newcapacity = q1->capacity == 0 ? 4 : 2 * q1->capacity;QueueData* tmp = (QueueData*)realloc(q1->vals,sizeof(QueueData) * newcapacity);assert(tmp);q1->vals = tmp;q1->capacity = newcapacity;}q1->vals[q1->rear] = e;q1->rear++;
}
判断队列是否为空
队列为空的情况很简单,当rear和front相等的时候队列为空
bool SeqQueueEmpty(queue* q1)
{return q1->front == q1->rear;
}
顺序队列的出队列操作
当数据出队列后,front需要指向新的队头元素,完成这个要求的方法有两种。
(1)当队头元素出队列后,将front的指针指向下一个元素
这种方法会导致队列的部分空间被浪费掉。
(2)
将队列的队头的位置保持不变,将后面的所有元素向前移动一位
这种处理方法虽然没有浪费空间,但是可以发现删除数据的时间复杂度到了O(N),也是存在不小的缺点
void SeqQueuePop(queue* q1)//方法1
{if (SeqQueueEmpty(q1)){perror("Queue is empty\n");exit(1);}q1->front++;
}
顺序队列操作的所有代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>#define MAXSIZE 10
typedef int QueueData;
typedef struct queue
{QueueData* vals;int front;int rear;int capacity;
}queue;void SeqQueueInit(queue* q1);
void SeqQueueDestory(queue* q1);void SeqQueuePush(queue* q1,QueueData e);
void SeqQueuePop(queue* q1);QueueData SeqQueueFront(queue* q1);
bool SeqQueueEmpty(queue* q1);
bool SeqQueueFull(queue* q1);void SeqQueueInit(queue* q1)
{q1->vals = NULL;q1->front = 0;q1->rear = 0;q1->capacity = 0;
}
void SeqQueueDestory(queue* q1)
{free(q1->vals);
}void SeqQueuePush(queue* q1, QueueData e)
{if (SeqQueueFull(q1))//判断队列是否满{//满则进行扩容int newcapacity = q1->capacity == 0 ? 4 : 2 * q1->capacity;QueueData* tmp = (QueueData*)realloc(q1->vals,sizeof(QueueData) * newcapacity);assert(tmp);q1->vals = tmp;q1->capacity = newcapacity;}q1->vals[q1->rear] = e;q1->rear++;
}
void SeqQueuePop(queue* q1)
{if (SeqQueueEmpty(q1)){perror("Queue is empty\n");exit(1);}q1->front++;
}QueueData SeqQueueFront(queue* q1)
{if (SeqQueueEmpty(q1)){perror("Queue is empty\n");exit(1);}return q1->vals[q1->front];
}bool SeqQueueEmpty(queue* q1)
{return q1->front == q1->rear;
}
bool SeqQueueFull(queue* q1)
{return q1->rear == q1->capacity;
}
链式结构的队列
既然顺序队列有着空间存储要求大,删除的时间复杂度高的缺点,那么链式结构饿的队列能不能解决这些问题呢?
链式队列的初始化
我们创建一个队列节点的结构,再创建一个队列的整体结构,将队列元素储存在节点当中。
typedef int LQueueData;
typedef struct QueueNode
{LQueueData val;struct QueueNode* next;
}QueueNode;typedef struct ListQueue
{QueueNode* front;//指向队头QueueNode* rear;//指向队尾int size;//队列大小
}ListQueue;
链式队列的初始化
根据使用需求对队列中的元素进行初始化,当链式队列为空队列时,队头与队尾指针都应该置为NULL。
void ListQueueInit(ListQueue* lq)
{lq->front = NULL;lq->rear = NULL;lq->size = 0;
}
链式队列的入队列操作
用尾插法,在队尾结点插入一个新的节点。
void ListQueuePush(ListQueue* lq, LQueueData e)
{//生成新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));newnode->val = e;newnode->next = NULL;if (ListQueueEmpty(lq)){lq->front = newnode;lq->rear = newnode;lq->size++;return;}//尾插法lq->rear->next = newnode;lq->rear = newnode;lq->size++;}
链式队列的出队列的操作
将front指针指向的节点释放,并将front指针指向下一个节点的位置
void ListQueuePop(ListQueue* lq)
{if (ListQueueEmpty(lq)){perror("Queue is empty\n");exit(1);}QueueNode* del = lq->front;lq->front = lq->front->next;lq->size--;free(del);
}
链式队列的所有代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int LQueueData;
typedef struct QueueNode
{LQueueData val;struct QueueNode* next;
}QueueNode;typedef struct ListQueue
{QueueNode* front;//指向队头QueueNode* rear;//指向队尾int size;//队列大小
}ListQueue;void ListQueueInit(ListQueue* lq);
void ListQueueDestory(ListQueue* lq);void ListQueuePush(ListQueue* lq,LQueueData e);
void ListQueuePop(ListQueue* lq);bool ListQueueEmpty(ListQueue* lq);
LQueueData ListQueueFront(ListQueue* lq);int ListQueueSize(ListQueue* lq);void ListQueueInit(ListQueue* lq)
{lq->front = NULL;lq->rear = NULL;lq->size = 0;
}
void ListQueueDestory(ListQueue* lq)
{QueueNode* cur = lq->front;while (cur){QueueNode* del = cur;cur = cur->next;free(del);}
}void ListQueuePush(ListQueue* lq, LQueueData e)
{//生成新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));newnode->val = e;newnode->next = NULL;if (ListQueueEmpty(lq)){lq->front = newnode;lq->rear = newnode;lq->size++;return;}//尾插法lq->rear->next = newnode;lq->rear = newnode;lq->size++;}
void ListQueuePop(ListQueue* lq)
{if (ListQueueEmpty(lq)){perror("Queue is empty\n");exit(1);}QueueNode* del = lq->front;lq->front = lq->front->next;lq->size--;free(del);
}bool ListQueueEmpty(ListQueue* lq)
{if (lq->front == NULL){lq->rear = NULL;return true;}return false;
}
LQueueData ListQueueFront(ListQueue* lq)
{if (ListQueueEmpty(lq)){perror("Queue is empty\n");exit(1);}return lq->front->val;
}int ListQueueSize(ListQueue* lq)
{return lq->size;
}