队列:
队列和栈一样也是一种表,但是他与栈不同的是在一段插入数据,在另一端删除数据。
队列基本操作是入队(enqueue),以及出队(dequeue),入队在表的队尾(rear)插入元素,出队是在队头(front)删除或返回一个元素。
队列和栈一样都可以用任何表来实现,本文选择用链表实现队列。
队列结构:
typedef int DataType;
typedef struct QueueNode {
DataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;//定义头和尾
队列接口函数:
void QueueInit(Queue* pq);//队列初始化
void QueueDestory(Queue* pq);//销毁队列
void QueuePush(Queue* pq, DataType x);//入队
void QueuePop(Queue* pq);//出队
bool QueueEmpty(Queue* pq);//队列是否为空
size_t QueueSize(Queue* pq);//队列元素
DataType QueueFront(Queue* pq);//头元素
DataType QueueBack(Queue* pq);//尾元素
队列初始化与销毁:
void QueueInit(Queue* pq) {
assert(pq);
pq->head = pq->tail = NULL;
}//初始化
void QueueDestory(Queue* pq) {
assert(pq);
QNode* cur = pq->head;
while (cur) {//对每一个元素进行free
QNode* next = cur->next;
free(cur);
cur = cur->next;
}
pq->head = pq->tail = NULL;
}//销毁
出队和入队:
void QueuePush(Queue* pq, DataType x) {
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL) {//当无任何元素时
assert(pq->head == NULL);
pq->head = pq->tail = newnode;
}
else {
pq->tail->next = newnode;
pq->tail = newnode;
}
}//入队
void QueuePop(Queue* pq) {
assert(pq);
assert(pq->head && pq->tail);
if (pq->head->next == NULL)//当只有对头元素时
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
其他函数:
bool QueueEmpty(Queue* pq) {
return pq->head == NULL;
}//判断是否为空
size_t QueueSize(Queue* pq) {
assert(pq);
QNode* cur = pq->head;
size_t size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}//返回队列元素数量
DataType QueueFront(Queue* pq) {
assert(pq);
assert(pq->head);
return pq->head->data;
}//返回对头元素
DataType QueueBack(Queue* pq) {
assert(pq);
assert(pq->tail);
return pq->tail->data;
}//返回队尾元素
测试函数:
#include"Queue.h"
void Test1() {
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
}
int main() {
Test1();
return 0;
}
循环队列:
由于队列需要不断的增减元素,为了减少空间浪费可以采用循环队列,其结构如图所示。
力扣连接:设计循环队列
创建一个数组,数组大小一定,定义一个头和尾。
front表示队头,tail表示队尾,进入一个元素tail++,删除一个元素时front++。
而因为不管队列为满或为空时front都等于tail,所以无法区分队列何时为空何时为满,为此加入一个空元素,此时可以区分出空和满的情况。
当front+1 == tail时表示循环链表为满,当tail == front 时表示数组为空。
typedef struct {
int* a;
int front;
int tail;
int k;
} MyCircularQueue;
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a =(int*) malloc(sizeof(int)*(k + 1));//要存储k个元素就需要k+1份空间
obj->front = obj->tail = 0;
obj->k = k;
return obj;
}//初始化队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if (myCircularQueueIsFull(obj)) {
return false;
}
obj->a[obj->tail] = value;
if (obj->tail == obj->k) {
obj->tail = 0;
}//当tail == k时也就是tail走到最后一位时需要退回到第一位
else {
obj->tail++;
}
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj)){
return false;
}
if (obj->front == obj->k) {
obj->front = 0;
}//front走到k时需要退回到0处
else {
obj->front++;
}
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj)) {
return -1;
}
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj)) {
return -1;
}
if (obj->tail == 0){
return obj->a[obj->k];
}//如果tail在0处时队尾元素在k位置处
else{
return obj->a[obj->tail - 1];
}
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj){
return obj->front == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj){
if(obj->tail == obj->k && obj->front == 0) {
return true;
}
else{
return obj->tail + 1 == obj->front;
}
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}