(1)链队列:用链表表示的队列。
(2)队列组成
首先说一下队列的节点。队列的节点是由数据data和存放地址的指针变量next两部分组成。
typedef struct QNode
{
int data;
struct QNode *next;
}QNode,*QueuePtr;
对于队列来说,要有对头指针front和队尾指针rear。并且这两个指针都是要指向队列的节点的。所以应该定义成结构体的指针类型。
typedef struct
{
QueuePtr front;//对头指针
QueuePtr rear;//队尾指针
}LinkQueue;
在写这个结构体的时候脑袋突然短路一下。我在想,用QueuePtr定义的front和rear这两个指针变量里面是否也有data和next两部分。查阅资料后才发现不是那么回事。(C语言中指针变量所占字节大小)
(3)队列的基本操作1、初始化队列
就是构造一个空队列。它的判断条件是:头指针和尾指针都指向头节点。如图所示:
/*--------------------------------------------------------------------------
操作目的: 初始化队列
初始条件: 无
操作结果: 构造一个空队列(空队列的判断条件为:头指针和尾指针均指向头节点)
函数参数: LinkQueue *Q
返回值: 无
--------------------------------------------------------------------------*/
void InitQueue(LinkQueue *Q)
{
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
if(Q->front == NULL)
{
printf("内存分配失败\n");
exit(-1);
}
else
{
Q->front->next = NULL;//将对头指针指向的节点的next赋为NULL
//Q->rear->next = NULL;//因为对头指针和队尾指针指向同一节点所以这两句写一句就可以
//问题1、一个变量的同类型的指针变量怎样存储此变量?
printf("分配内存成功\n");
}
}
首先申请一块内存空间,
关于malloc和free函数的用法中,当申请空间后首先要判断是否申请内存成功。当判断成功之后才进行下一步操作。
2、销毁队列
怎样才算是销毁队列呢?就是将队列的元素全部释放掉之后,将front和rear两个指针都指向NULL。
/*------------------------------------------------------------
操作目的: 销毁队列
初始条件: 队列Q存在
操作结果: 销毁队列Q
函数参数: 待销毁的队列Q
返回值: 无
-------------------------------------------------------------*/
void DestroyQueue(LinkQueue *Q)
{
while(Q->front != NULL)
{
Q->rear = Q->front->next;
free(Q->front);
Q->front = Q->rear;
}
printf("销毁队列成功");
return ;
}
利用Q->front 是否等于NULL作为判断条件。首先将front指向的元素的下一个元素赋给rear。然后将front指向的元素释放。最后通过,Q->front = Q->rear将Q->front向下移动。通过这样的方式逐个释放队列的元素。当Q->front = NULL时,Q->rear 也就等于 NULL。
3、队列判空
此操作函数比较简单,就是判断对头指针是否等于队尾指针即可(Q->front == Q->rear)。如果等于返回true,否则返回false.
/*---------------------------------------------------
操作目的: 队列判空
初始条件: 队列Q存在
操作结果: 判断队列是否为空
函数参数: 队列Q
返回值: true,false
----------------------------------------------------*/
bool QueueEmpty(LinkQueue *Q)
{
if(Q->front == Q->rear)
return true;
else
return false;
}
4、队列清空
队列清空与销毁队列的不同之处就是:队列清空保留头节点,并使对头指针front和队尾指针rear指向头节点,形成空队列。
/*---------------------------------------------------
操作目的: 将队列清空
初始条件: 队列Q存在
操作结果: 将队列Q清为空队列
函数参数: 队列Q
返回值: 无
----------------------------------------------------*/
void ClearQueue(LinkQueue *Q)
{
QueuePtr p = Q->front->next;
if(QueueEmpty(Q))
{
printf("队列不为空\n");
}
else
{
while(p != NULL)
{
Q->front->next = p->next;
free(p);
p = Q->front->next;
}
Q->rear = Q->front;//形成空队列(即对头、队尾指向头结点)
}
return ;
}
5、求队列的长度
求队列的长度时,首先应该判断一下时候为空队列。如果为空队列就不用再求队列的长度了。如果不是空队列,在进行下一步操作。
int QueueLength(LinkQueue *Q)
{
int length = 0;
QueuePtr p = Q->front;
if(QueueEmpty(Q))
{
printf("队列为空队列");
exit(-1);
}
else
{
while(p != Q->rear)
{
length ++;
p = p->next;
}
}
return length;
}
6、求队列对头的元素
要判断是否为空队列。
7、插入元素
队列插入元素只能在队尾。因此在插入节点的时候,让队尾指针指向的节点的next指向要插入的节点。之后,将队尾指针指向刚插入的节点。
/*-----------------------------------------------------
操作目的: 插入元素
初始条件: 队列Q存在
操作结果: 向队列Q中插入一个元素e
函数参数: 队列Q,待插入元素e
返回值: 无
------------------------------------------------------*/
void InsertQueue(LinkQueue *Q, int e)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if(p == NULL)
{
printf("动态分配内存失败");
exit(-1);
}
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
return ;
}
插入队列如图所示:
8、删除元素
首相定义一个指针变量p,让它指向对头指针front指向的下一个元素。然后通过Q->front->next = p->next;可将p指向的节点删除。这里面有个特殊情况,就是当p指向的节点与队尾指针指向的节点为同一节点(队列中只有一个元素时),可以直接 Q->rear = Q->front;即可。
/*-----------------------------------------------------
操作目的: 删除元素
初始条件: 队列Q存在
操作结果: 从队列Q中删除一个元素
函数参数: 队列Q,待存放删除元素的变量e
返回值: true,false
-------------------------------------------------------*/
bool DeQueue(LinkQueue *Q, int *e)
{
QueuePtr p = Q->front->next;
if(QueueEmpty(Q))
{
return false;
}
else
{
Q->front->next = p->next;
*e = p->data;
if(Q->rear == p)
Q->rear = Q->front;
return true;
}
}
删除元素如图所示:
9、遍历队列
首先判断队列是否为空队列。若不为空队列,在进行下一步操作
bool QueueTraverse(LinkQueue *Q)
{
QueuePtr p = Q->front->next;
if(QueueEmpty(Q))
{
return false;
}
else
{
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
return true;
}
}
10、完整的代码
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
typedef struct QNode
{
int data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;//对头指针
QueuePtr rear;//队尾指针
}LinkQueue;
/*--------------------------------------------------------------------------
操作目的: 初始化队列
初始条件: 无
操作结果: 构造一个空队列(空队列的判断条件为:头指针和尾指针均指向头节点)
函数参数: LinkQueue *Q
返回值: 无
--------------------------------------------------------------------------*/
void InitQueue(LinkQueue *Q)
{
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
if(Q->front == NULL)
{
printf("内存分配失败\n");
exit(-1);
}
else
{
Q->front->next = NULL;//将对头指针指向的节点的next赋为NULL
//Q->rear->next = NULL;//因为对头指针和队尾指针指向同一节点所以这两句写一句就可以
//问题1、一个变量的同类型的指针变量怎样存储此变量?
printf("分配内存成功\n");
}
}
/*------------------------------------------------------------
操作目的: 销毁队列
初始条件: 队列Q存在
操作结果: 销毁队列Q
函数参数: 待销毁的队列Q
返回值: 无
-------------------------------------------------------------*/
void DestroyQueue(LinkQueue *Q)
{
while(Q->front != NULL)
{
Q->rear = Q->front->next;
free(Q->front);
Q->front = Q->rear;
}
printf("销毁队列成功");
return ;
}
/*---------------------------------------------------
操作目的: 队列判空
初始条件: 队列Q存在
操作结果: 判断队列是否为空
函数参数: 队列Q
返回值: true,false
----------------------------------------------------*/
bool QueueEmpty(LinkQueue *Q)
{
if(Q->front == Q->rear)
return true;
else
return false;
}
/*---------------------------------------------------
操作目的: 将队列清空
初始条件: 队列Q存在
操作结果: 将队列Q清为空队列
函数参数: 队列Q
返回值: 无
----------------------------------------------------*/
void ClearQueue(LinkQueue *Q)
{
QueuePtr p = Q->front->next;
if(QueueEmpty(Q))
{
printf("队列不为空\n");
}
else
{
while(p != NULL)
{
Q->front->next = p->next;
free(p);
p = Q->front->next;
}
Q->rear = Q->front;//形成空队列(即对头、队尾指向头结点)
}
return ;
}
/*-----------------------------------------------------
操作目的: 求队列的长度
初始条件: 队列Q存在
操作结果: 返回Q的元素个数即为队列的长度
函数参数: 队列Q
返回值: Length数据元素的个数
------------------------------------------------------*/
int QueueLength(LinkQueue *Q)
{
int length = 0;
QueuePtr p = Q->front;
if(QueueEmpty(Q))
{
printf("队列为空队列");
exit(-1);
}
else
{
while(p != Q->rear)
{
length ++;
p = p->next;
}
}
return length;
}
/*-----------------------------------------------------
操作目的: 求对头元素
初始条件: 队列Q存在
操作结果: 得到对头元素
函数参数: 队列Q,存放对头元素的e
返回值: false,true
------------------------------------------------------*/
bool GetHead(LinkQueue *Q, int *e)
{
if(QueueEmpty(Q))
{
return false;
}
else
{
*e = Q->front->next->data;
return true;
}
}
/*-----------------------------------------------------
操作目的: 插入元素
初始条件: 队列Q存在
操作结果: 向队列Q中插入一个元素e
函数参数: 队列Q,待插入元素e
返回值: 无
------------------------------------------------------*/
void InsertQueue(LinkQueue *Q, int e)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if(p == NULL)
{
printf("动态分配内存失败");
exit(-1);
}
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
return ;
}
/*-----------------------------------------------------
操作目的: 删除元素
初始条件: 队列Q存在
操作结果: 从队列Q中删除一个元素
函数参数: 队列Q,待存放删除元素的变量e
返回值: true,false
-------------------------------------------------------*/
bool DeQueue(LinkQueue *Q, int *e)
{
QueuePtr p = Q->front->next;
if(QueueEmpty(Q))
{
return false;
}
else
{
Q->front->next = p->next;
*e = p->data;
if(Q->rear == p)
Q->rear = Q->front;
return true;
}
}
/*-----------------------------------------------------
操作目的: 遍历队列
初始条件: 队列Q存在
操作结果: 遍历出队列的元素
函数参数: 队列Q
返回值: 无
-------------------------------------------------------*/
bool QueueTraverse(LinkQueue *Q)
{
QueuePtr p = Q->front->next;
if(QueueEmpty(Q))
{
return false;
}
else
{
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
return true;
}
}
int main()
{
int length,temp,temp_save;
LinkQueue Queue;
InitQueue(&Queue);
if(QueueEmpty(&Queue))
{
printf("队列为空\n");
}
else
printf("队列不为空\n");
//DestroyQueue(&Queue);
InsertQueue(&Queue, 1);
InsertQueue(&Queue, 2);
InsertQueue(&Queue, 3);
InsertQueue(&Queue, 4);
InsertQueue(&Queue, 5);
QueueTraverse(&Queue);
length = QueueLength(&Queue);
printf("\n");
printf("链队列的个数为:%d\n",length);
if(GetHead(&Queue, &temp))
{
printf("%d\n",temp);
}
if(DeQueue(&Queue, &temp_save))
{
printf("%d\n",temp_save);
}
QueueTraverse(&Queue);
ClearQueue(&Queue);
if(QueueEmpty(&Queue))
{
printf("队列为空\n");
}
else
printf("队列不为空\n");
}