一、队列
(1)队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为
队尾
出队列:进行删除操作的一端称为
队头
(2)队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。
头文件部分:
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QNode//构建一个结构体,用于创建每一个结点
{
QDataType val;
struct QNode* next;
}QNode;
typedef struct Queue//创建一个结构体,表示队列的头和尾
{
QNode* head;
QNode* tail;
int size;
}Queue;
//初始化
void QInit(Queue* pq);
//销毁
void QDestroy(Queue* pq);
//插入
void QPush(Queue* pq, QDataType x);
//删除
void QPop(Queue* pq);
//队头的数据
QDataType QFront(Queue* pq);
//队尾的数据
QDataType QBack(Queue* pq);
//判断是否为空
bool QEmpty(Queue* pq);
//队列的大小
size_t Qsize(Queue* pq);
函数的实现部分:
#include"Queue.h"
//初始化
void QInit(Queue* pq) //初始化的时候有不同的方法,可以先给顺序表先开辟一定的空间
//当开辟一定空间了后,在后面的插入的部分,就可以不必判定顺序表是否为空
{
assert(pq);
//检查pq是否为空指针,因为当pq为指针了后,后面的语句要对pq进行运用,就会存在对空指针的调用--即野指针的问题
pq->head = NULL;
pq->tail = NULL;
pq->size = 0;
}
//销毁
void QDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
}
pq->head = pq->tail = NULL; //防止野指针的访问
pq->size = 0;
}
//判断是否为空
bool QEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;
}
//插入
void QPush(Queue* pq, QDataType x)
{
assert(pq);
QNode* new = (QNode*)malloc(sizeof(QNode));//开辟一个新的点,用来存放要插入的值--x
if (new == NULL)//检查机制,因为malloc可能没有开辟空间
{
perror("malloc fail");//当没有开辟的时候,给我们报错,说明空间没有开辟成功
exit(-1);
}
new->val = x;
new->next = NULL;
//当队列原本没有数据时,即size = 0;
if (pq->head == NULL)
{
pq->head = pq->tail = new;
}
else
{
pq->tail->next = new;
pq->tail = new;
}
pq->size++;
}
//删除
void QPop(Queue* pq)
{
assert(pq);
assert(!QEmpty(pq));//当顺序表为空的时候,不能进行删数据
if (pq->head->next == NULL)//当只存在一个数据的时候
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* del = pq->head;
pq->head = pq->head->next;
free(del);
}
pq->size--;
}
//队头的数据
QDataType QFront(Queue* pq)
{
assert(pq);
assert(pq->head != NULL);
return pq->head->val;
}
//队尾的数据
QDataType QBack(Queue* pq)
{
assert(pq);
assert(pq->tail != NULL);
return pq->tail->val;
}
//队列的大小
size_t Qsize(Queue* pq)
{
//在构建顺序表的时候,如果我们没有设定一个size来进行对插入删除的统计时,就采用第二种方法
assert(pq);
return pq->size;
//(2)
//int count = 0;
//QNode* cur = pq->head;
//while (cur)
//{
// count++;
// cur = cur->next;
//}
//return count;
}
循环队列:
可以用链表来进行实现,也可以用数组进行实现。
此时实现以数组的方式:
typedef struct
{
int front;//指向第一个元素
int rear;//指向最后一个元素的下一个位置
int capacity;//数组的大小
int *elements;//开辟的数组
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue *obj = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));
obj->capacity = k + 1;//多开一个空间,解决判满的问题
obj->rear = obj->front = 0;//当数据满了的时候,总的大小应该是k+1
obj->elements = (int *)malloc(sizeof(int) * obj->capacity);
return obj;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if ((obj->rear + 1) % obj->capacity == obj->front)
{ //当空间满了后不能继续插入
return false;
}
obj->elements[obj->rear] = value;
obj->rear = (obj->rear + 1) % obj->capacity;//更新rear的位置
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if (obj->rear == obj->front) //当没有元素的时候不能进行删除
{
return false;
}
obj->front = (obj->front + 1) % obj->capacity;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if (obj->rear == obj->front) //没有元素的时候
{
return -1;
}
return obj->elements[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if (obj->rear == obj->front)
{
return -1;
}
return obj->elements[(obj->rear - 1 + obj->capacity) % obj->capacity];
//通过rear的位置来寻找最后一个元素的位置
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->rear == obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->rear + 1) % obj->capacity == obj->front;
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->elements);
free(obj);
}