观看这里的uu建议先看顺序表和链表相关内容
线性表之顺序表
线性表之单链表
线性表之双链表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列等。
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
队列是一种特殊的线性表,既可以以数组形式存储也可以以链式结构的形式存储。以数组形式存储称为数组队列(特殊的线性表),以链式结构的形式存储称为链式队列(特殊的链表)。
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列的原则。
队尾:进行插入操作的一端。
队头:进行删除操作的一端。
队列是从队尾插入数据,队尾不能删除数据。
从队头删除数据,队头不能插入数据。
队列分为数组队列和链式队列。
数组队列:以数组形式存储的队列。
链式队列:以链式结构的形式存储的队列。
与栈不同,数组栈和双链式栈实现的效率和性能都比较好,但是对于队列而言,数组队列相比链式队列基本没有优势。
数组队列的缺点:
链式队列与以前的单链表有一点不同,那就是链式队列需要两个指针,一个是头指针,一个是尾指针,头指针用来操作头部数据相关的功能,尾指针用来操作尾部数据相关的功能。因此需要再定义一个结构体来保存头指针和尾指针这两个成员变量。实际上一般的单链表也可以定义尾指针,但是一般的单链表定义尾指针没有太大价值,所以不定义。
队列头文件Queue.h的声明如下:
#pragma once
#include
#include
#include
typedef int QDataType;
// 链式结构:表示队列
typedef struct QListNode
{
QDataType data;
struct QListNode* pNext;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 动态申请一个节点
QNode* BuyQNode(QDataType x);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType x);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue * q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
//打印
void QueuePrint(Queue* q);
队列的实现大部分是链表中的一些操作,这里不做详细解释,只给源码和某些函数调试结果。
函数的实现思路在代码注释中已详细解释。
初始化函数在Queue.c中如下:
// 初始化队列
void QueueInit(Queue* q)
{
q->head = q->head->pNext = NULL;
q->tail = q->tail->pNext = NULL;
}
申请节点函数在Queue.c中如下:
// 动态申请一个节点
QNode* BuyQNode(QDataType x)
{
//开辟空间
QNode* newnode = (QNode*)malloc(sizeof(QNode));
//开辟失败,打印开辟失败并退出程序
if (newnode == NULL)
{
printf("malloc fail");
exit(-1);
}
//开辟成功赋值即可
else
{
newnode->data = x;
newnode->pNext = NULL;
}
}
销毁函数在Queue.c中如下:
// 销毁队列
void QueueDestroy(Queue* q)
{
//当前节点为头节点
QNode* cur = q->head;
//遍历队列当前节点为空结束遍历
while (cur != NULL)
{
//先保存当前节点的下一节点
QNode* next = cur->pNext;
//释放当前节点
free(cur);
//移动当前节点位置
cur = next;
}
//置0
q->head = q->tail = NULL;
}
以上函数与链表中的基本相同。
入队函数在Queue.c中如下:
// 队尾入队列
void QueuePush(Queue* q, QDataType x)
{
//申请节点
QNode* newnode = BuyQNode(x);
//如果队列不为空
if (!QueueEmpty(q))
{
//队尾的下一节点为新节点
q->tail->pNext = newnode;
//队尾变为新节点
q->tail = newnode;
}
//如果队列为空
else
{
//队头队尾都为新节点
q->head = q->tail = newnode;
}
}
出队函数在Queue.c中如下:
// 队头出队列
void QueuePop(Queue* q)
{
//不为空时才可删除
assert(QueueEmpty == 0);
//保存当前队头值
QNode* cur = q->head;
//队头变为队头的下一节点
q->head = q->head->pNext;
//释放原来队友的空间
free(cur);
cur = NULL;
}
判断队列是否为空函数在Queue.c中如下:
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
//头为空返回1,不为空返回0
return q->head == NULL;
}
具体使用方式如下:
#include
#include
#include
#include
#include "Queue.h"
//入队出队
void QueueTest1()
{
//定义一个队列结构体
Queue qu ;
//初始化队列
QueueInit(&qu);
//入队1234
QueuePush(&qu, 1);
QueuePush(&qu, 2);
QueuePush(&qu, 3);
QueuePush(&qu, 4);
//出队12
QueuePop(&qu);
QueuePop(&qu);
//再出队三次会报错
QueuePop(&qu);
QueuePop(&qu);
QueuePop(&qu);
}
int main()
{
QueueTest1();
return 0;
}
执行调试结果如下:
1·从队尾存入1234,并对相应变量进行监测:
2·以上面情况为基础,从队头出队两次,并对相应变量进行监测:
3·以上面情况为基础,再从队头出队三次,并对相应变量进行监测:
当前只有两个数据却出队三次,因此程序中断并报错。
获取队头元素在Queue.c中如下:
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
//不为空可获取
assert(QueueEmpty(q) == 0);
return q->head->data;
}
获取队尾元素在Queue.c中如下:
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
//不为空可获取
assert(!QueueEmpty(q) == 0);
return q->tail->data;
}
具体使用方式如下:
#include
#include
#include
#include
#include "Queue.h"
//获取队头、队尾元素
void QueueTest2()
{
//定义一个队列结构体
Queue qu;
//初始化队列
QueueInit(&qu);
//入队1234
QueuePush(&qu, 1);
QueuePush(&qu, 2);
QueuePush(&qu, 3);
QueuePush(&qu, 4);
//获取队头元素
QDataType Head = QueueFront(&qu);
//获取队尾元素
QDataType Tail = QueueBack(&qu);
}
int main()
{
QueueTest2();
return 0;
}
执行调试结果如下:
从队尾存入1234,获取队头队尾元素并对相应变量进行监测:
当前队列元素个数函数在Queue.c中如下:
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
QNode* cur = q->head;
int i = 0;
//遍历队列
while (cur != NULL)
{
i++;
//移动当前指针
cur = cur->pNext;
}
return i;
}
具体使用方式如下:
#include
#include
#include
#include
#include "Queue.h"
// 获取队列中有效元素个数
void QueueTest3()
{
//定义一个队列结构体
Queue qu;
//初始化队列
QueueInit(&qu);
//入队1234
QueuePush(&qu, 1);
QueuePush(&qu, 2);
QueuePush(&qu, 3);
QueuePush(&qu, 4);
//获取队列有效元素个数
int geshu = QueueSize(&qu);
}
int main()
{
QueueTest3();
return 0;
}
执行调试结果如下:
从队尾存入1234,获取队列元素个数并对相应变量进行监测:
打印函数在Queue.c中如下:
//打印
void QueuePrint(Queue* q)
{
assert(!QueueEmpty(q));
//打印完以数据出队一个数据
while (!QueueEmpty(q))
{
printf("%d ", q->head->data);
QueuePop(q);
}
}
具体使用方式如下:
// 打印
void QueueTest4()
{
//定义一个队列结构体
Queue qu;
//初始化队列
QueueInit(&qu);
//入队1234
QueuePush(&qu, 1);
QueuePush(&qu, 2);
QueuePush(&qu, 3);
QueuePush(&qu, 4);
//打印出队
QueuePrint(&qu);
}
int main()
{
QueueTest4();
return 0;
}