5. 队列 - 队列存储结构及算法实现
5.1 队列 - 基本概念
队列
是两端都开口"的线性储存结构,要求数据只能从一端进,从另一端出
,遵循"先进先出"
的原则。- 队列存储结构的实现有以下两种方式:
顺序队列
:在顺序表的基础上实现的队列结构。链队列
:在链表的基础上实现的队列结构。
5.2 队列 - 顺序表实现队列存储结构
- 顺序队列的底层使用的是
数组
,因此需预先申请一块足够大的内存空间初始化顺序队列。为了满足顺序队列中数据从队尾进,队头出且先进先出的要求,我们还需要定义两个指针(top 和 rear)分别用于指向顺序队列中的队头元素和队尾元素
。 - 如果数据在数组中位置只向后移动,整个顺序队列在数据不断地进队出队过程中,在顺序表中的位置不断后移,存储区会不停的扩大,因此实际中
存储数组循环存储
,相当于存储区域是一个环形结构
。 - 顺序表实现队列存储结构如下:
#include <stdio.h>
#include <stdlib.h>
#include<stdint.h>
typedef struct QueueDefine {
uint8_t* QueueAdress; // 存储地址
uint16_t top; // 队头
uint16_t rear; // 队尾
uint16_t size; // 队列容量
uint8_t FullOrEmptyflag; //解决取存中top和rear重合时为空或者为满的情况,1为满
}Queue;
/**
* Discribe : 创建一个队列
* Input : size -> 创建队列的容量尺寸
* return : 申请队列的地址
**/
Queue CreateQueue(uint16_t size) {
Queue QueueCreate;
QueueCreate.QueueAdress = (uint8_t*)malloc(size * sizeof(uint8_t));
memset(QueueCreate.QueueAdress, 0xff, size);
QueueCreate.top = 0;
QueueCreate.rear = 0;
QueueCreate.size = size;
QueueCreate.FullOrEmptyflag = 0;
return QueueCreate;
}
/**
* Discribe : 判断队列是否为空或者满
* Input : queue -> 存储队列
* return : 1 -> 队列为满 , 0 -> 队列为空
**/
uint8_t QueueIsEmptyOrFull(Queue* queue) {
return queue->FullOrEmptyflag;
}
/**
* Input : queue->存储队列
* return : 队列可存储空间
* */
uint16_t GetQueueSpace(Queue* queue) {
if (queue->top == queue->rear) {
return QueueIsEmptyOrFull(queue) ? 0 : queue->size ;
}
if (queue->top < queue->rear) {
return queue->size - (queue->rear - queue->top );
}else {
return queue->top - queue->rear;
}
}
/**
* Discribe : 数据入队
* Input : queue -> 存储队列, data -> 入队数据, length -> 入队长度
* return : 1 -> 入队成功 , 0 -> 入队失败
**/
uint8_t EnterQueue(Queue* queue, uint8_t* data, uint8_t length) {
if (data == NULL || length < 1) {
printf("入队数据有误!!!\n");
return 0;
}
if (GetQueueSpace(queue) < length) {
printf("队列空间不足, space = %d, data length = %d!!!\n", GetQueueSpace(queue), length);
return 0;
}
for (uint16_t i = 0; i < length; i++) {
queue->QueueAdress[queue->rear % queue->size] = data[i];
queue->rear = ((queue->rear + 1) % queue->size);
if (queue->top == queue->rear) {
queue->FullOrEmptyflag = 1;
}
}
}
/**
* Discribe : 数据出队
* Input : queue -> 存储队列, data -> 出队存放地址, length -> 出队长度
* return : 1 -> 出队成功 , 0 -> 出队失败
**/
uint8_t LeaveQueue(Queue* queue, uint8_t* data, uint8_t length) {
if (data == NULL || length < 1) {
printf("出队数据指令有误!!!\n");
return 0;
}
if ((queue->size - GetQueueSpace(queue)) < length) {
printf("取出数据长度大于队列存储数据长度, save size = %d, data length = %d!!!\n", queue->size - GetQueueSpace(queue), length);
return 0;
}
for (uint16_t i = 0; i < length; i++) {
data[i] = queue->QueueAdress[queue->top % queue->size];
queue->QueueAdress[queue->top % queue->size] = 0xff;
queue->top = ((queue->top + 1 ) % queue->size);
if (queue->top == queue->rear) {
queue->FullOrEmptyflag = 0;
}
}
}
void display(Queue* queue) {
printf("队列空间存储内容为(ff无效值):");
for (uint16_t i = 0; i < queue->size; i++) {
printf("%x ", queue->QueueAdress[i]);
}
printf("[ top = %d , rear = %d ]", queue->top, queue->rear);
printf(" 队列空间 space = %d !\n\n", GetQueueSpace(queue));
}
int main() {
Queue quece = CreateQueue(10);
printf("创建了一个容量为 :%d 的队列!\n", quece.size);
display(&quece);
uint8_t data[10] = {0};
for (uint16_t i = 0; i < 10; i++) {
data[i] = i + 1;
}
EnterQueue(&quece, data, 2);
display(&quece);
EnterQueue(&quece, &data[2], 8);
display(&quece);
uint8_t getdata[10] = { 0 };
LeaveQueue(&quece, getdata, 3);
display(&quece);
LeaveQueue(&quece, getdata, 7);
display(&quece);
EnterQueue(&quece, data, 5);
display(&quece);
return 0;
}
在存取时会遇到top和rear重合的情况,如下示意图所示,因此上述方法中引入一个存储标志来解决取存中top和rear重合时为空或者为满的情况,当入队时遇到重合,则只可能为满,同理出队遇到重合为空
- 直接用数组和指针实现方法
#include <stdio.h>
#include <stdlib.h>
#include<stdint.h>
#define BUFFER_LENGTH 2048
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
void FifoQueueInit();
BOOL FifoQueueIsEmpty();
BOOL FifoQueueIsFull();
int GetFifoQueueSize();
int GetFifoQueueSpace();
int FifoQueueInster(unsigned char Datas[], int nSize);
int FifoQueuePopup(unsigned char Datas[], int nSize);
static unsigned char FifoQueueBuffer[BUFFER_LENGTH + 1]; // 存储队列
static unsigned char* pFifoQueueHead = FifoQueueBuffer; // 头指针
static unsigned char* pFifoQueueTail = FifoQueueBuffer; // 尾指针
void FifoQueueInit() // 初始化队列
{
memset(FifoQueueBuffer, 0x00, BUFFER_LENGTH + 1);
pFifoQueueHead = FifoQueueBuffer;
pFifoQueueTail = FifoQueueBuffer;
}
BOOL FifoQueueIsEmpty()
{
// 头尾指针指向同一个位置,则队列为空
return (pFifoQueueHead == pFifoQueueTail) ? TRUE : FALSE;
}
BOOL FifoQueueIsFull()
{
if (pFifoQueueTail == FifoQueueBuffer)
{ // 尾指针指向数组[0]位置
return ((pFifoQueueHead - pFifoQueueTail) == BUFFER_LENGTH) ? TRUE : FALSE;
}
else
{ // 头执政在前,尾指针紧随其后
return (pFifoQueueHead == pFifoQueueTail - 1) ? TRUE : FALSE;
}
}
int GetFifoQueueSize() // 已存长度
{
if (pFifoQueueHead >= pFifoQueueTail)
{ // 头指针在前
return pFifoQueueHead - pFifoQueueTail;
}
else
{ // 头指针在后
return (BUFFER_LENGTH - (pFifoQueueTail - pFifoQueueHead - 1));
}
}
int GetFifoQueueSpace() // 剩余可存空间
{
return (BUFFER_LENGTH - GetFifoQueueSize());
}
int FifoQueueInster(unsigned char Datas[], int nSize)
{
int n = 0; // 统计存入数据长度
for (int i = 0; i < nSize; i++)
{
if (FifoQueueIsFull()) // 如果存储已满,停止存储
{
break;
}
(*pFifoQueueHead) = Datas[i];
if (pFifoQueueHead == FifoQueueBuffer + BUFFER_LENGTH) {
pFifoQueueHead = FifoQueueBuffer;
}
else {
pFifoQueueHead++;
}
n++;
}
return n;
}
int FifoQueuePopup(unsigned char Datas[], int nSize)
{
int i = 0;
int n = 0;
for (i = 0; i < nSize; i++)
{
if (FifoQueueIsEmpty())
{
break;
}
Datas[i] = (*pFifoQueueTail);
if (pFifoQueueTail == FifoQueueBuffer + BUFFER_LENGTH)
{
pFifoQueueTail = FifoQueueBuffer;
}
else
{
pFifoQueueTail++;
}
n++;
}
return n;
}
5.3 队列 - 链表实现队列存储结构
- 链式是
实时申请空间
,因此链式队列就不需要考虑空间利用的问题 - 链表实现队列存储结构如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct QNode{
int data;
struct QNode * next;
}QNode;
QNode * initQueue(){
QNode * queue = (QNode*)malloc(sizeof(QNode));
queue->next = NULL;
return queue;
}
QNode* enQueue(QNode * rear,int data){
QNode * enElem = (QNode*)malloc(sizeof(QNode));
enElem->data = data;
enElem->next = NULL;
// 使用尾插法向链队列中添加数据元素
rear->next = enElem;
rear = enElem;
return rear;
}
QNode* DeQueue(QNode * top,QNode * rear){
if (top->next == NULL) {
printf("队列为空!!!\n");
return rear;
}
QNode * p = top->next;
printf("%d ", p->data);
top->next = p->next;
if (rear == p) {
rear = top;
}
free(p);
return rear;
}
int main() {
QNode * queue,*top,*rear;
queue = top = rear = initQueue();// 创建头结点
// 向链队列中添加结点,使用尾插法添加的同时,队尾指针需要指向链表的最后一个元素
rear = enQueue(rear, 1);
rear = enQueue(rear, 2);
rear = enQueue(rear, 3);
rear = enQueue(rear, 4);
// 入队完成,所有数据元素开始出队列
rear = DeQueue(top, rear);
rear = DeQueue(top, rear);
rear = DeQueue(top, rear);
rear = DeQueue(top, rear);
rear = DeQueue(top, rear);
return 0;
}
感谢阅读 若有错误 敬请见谅!!!