顺序队列的基本操作
前面介绍用两个指针表示队列状态,为区别队空与队满状态,让front指针向前移动一个位置。
顺序结构定义:
typedef strct
{
datatype data[QUEUE_SIZE];
int front, rear;
}SeqQueue;
1.置空栈
按队空初始化条件 front = rear =QUEUE_SIZE-1 设置头尾指针。
程序实现:
/*======================================
函数功能:顺序队列置队空
函数输入:队列起始地址
函数输出:无
========================================*/
void initialize_SqQueue(SeqQueue *sq)
{
sq->front = QUEUE_SIZE-1;
sq->rear = QUEUE_SIZE-1;
}
2.判队空
根据对空条件 rear=front, 判断队列是否为空:队空返回1,;队非空返回0。
程序实现:
/*======================================
函数功能:顺序队列判队空
函数输入:队列起始地址
函数输出:1——队空;0——队非空
========================================*/
int Empty_SqQueue(SeqQueue *sq)
{ if ( sq->rear == sq->front ) return TRUE;
else return FALSE;
}
3.取队头元素
若队列非空,返回队头元素所在位置下标;否则返回-1.
程序实现:
/*======================================
函数功能:顺序队列取队头元素
函数输入:队列起始地址
函数输出:-1——队空标志;其他值——队头元素位置
========================================*/
int get_SqQueue(SeqQueue *sq )
{
if ( ! Empty_SqQueue(sq) )//队非空
return (sq->front+1) % QUEUE_SIZE;
return -1;//队空
}
4.入队
若队满,返回FALSE; 否则,队尾指针rear向后移一位,在rear指向处插入入队元素值。
/*======================================
函数功能:顺序队列元素入队
函数输入:队列起始地址,入队元素值
函数输出:0——队满,操作不成功;1——队非满,操作成功
========================================*/
int Insert_SqQueue(SeqQueue*sq, datatype x)
{
if(sq->front==(sq->rear+1)%QUEUE_SIZE)//判队满
return FALSE;
else
{
sq->rear=(sq->rear+1)%QUEUE_SIZE;//队尾指针向后移一位
sq->data[sq->rear]=x; //元素x入队
return TRUE;
}
}
5.出队
若队非空,头指针front向后移一位,返回front,否则返回队空标记-1。
注意出队操作和取队头元素的区别。
/*======================================
函数功能:顺序队列出队
函数输入:队列起始地址
函数输出:-1——队空标志;其他值——队头元素位置
========================================*/
int Delete_SqQueue(SeqQueue *sq)
{
if(!Empty_SqQueue(sq))//队非空
{
sq->front=(sq->front+1)%QUEUE_SIZE;
return sq->front;
}
return -1;//队空
}
链队列——问题引入
用循环队列实现杨辉三角形时,若没有队满的限制,将会面临数组溢出问题,这使得计算结果的规模会相应受限。
链队列定义:
用链表表示的队列(队列的链式存储结构),是限制仅在表头删除和表尾插入的单链表
队列的链式存储结构
链队列数据结构设计
链表列由单链表构成,头指针front指向头结点,尾指针rear指向尾指针,头尾指针组合在一个结构中,队列指针 lq 指向此结构。
1)链结点的数据类型描述
typedef struct node
{
datatype data;
struct node *next;
} LinkListNode;
2)链中头尾指针的数据类型描述
typedef struct
{
LinkListNode *front,*rear;
}LinkQueue;
3)链队列指针 lq 数据类型
LinkQueue *lq;
设置链队列 lq 指针的目的:
讨论:设置lq指针指向链队列头尾指针的组合结构,这样方便队列信息的完整传递。
链队列的基本操作
1.初始化置空队
首次建立只有一个头结点的链队列:
申请一结点;
结点的指针域置空;
队列的头尾指针均指向此结点。
函数malloc()分配一个大小为LinkListNode字节的空间,并将其首地址放入指针变量lq->front中。
/*======================================
函数功能:链队列初始化
函数输入:队列起始地址
函数输出:无
========================================*/
void initialize_LkQueue(LinkQueue *lq)
{
lq->front=(LinkListNode *) malloc(sizeof(LinkListNode));
lq->front->next=NULL;
lq->rear=lq->front;
}
2.判队空
若头尾指针相等返回队空标记TRUE;否则返回非空标记FALSE。
/*======================================
函数功能:链队列判队空
函数输入:队列起始地址
函数输出:1——队空;0——队非空
========================================*/
int Empty_LkQueue( LinkQueue *lq )
{
if ( lq->front == lq->rear) return TRUE;
else return FALSE;
}
3.取队头结点
返回是否成功标志,结点值。
若队列非空,取队头指针指向的结点值;
返回操作成功标志TRUE;
否则返回FALSE。
程序实现:
/*======================================
函数功能:链队列取队头结点
函数输入:队列起始地址,(队列结点值)
函数输出:0——队空;1——队非空
========================================*/
int Get_LkQueue(LinkQueue *lq, datatype *x)
{
if ( Empty_LkQueue(lq)) return FALSE; //队空
x = &(lq->front->next->data); //取队头结点值
return TRUE;
}
4.入队
申请新结点链入队尾;修改队列尾指针;新结点赋值x。
程序实现:
/*======================================
函数功能:链队列入队
函数输入:队列起始地址,入队列结点值
函数输出:无
========================================*/
void Insert_LkQueue(LinkQueue *lq, datatype x)
{
lq->rear->next=(LinkListNode *)malloc(sizeof( LinkListNode ));
//新结点链入队尾
lq->rear=lq->rear->next; //修改队列尾指针
lq->rear->data=x; //新结点赋值
lq->rear->next=NULL; //尾结点指针域置结束标志NULL
}
5.出队
伪代码描述:
若队列非空,找到队头结点s;
若队列只有一个结点,则队列置空;
摘下队头结点s,修改头结点指针域;
返回s的地址;
返回 NULL;
/*======================================
函数功能:链队列出队
函数输入:队列起始地址
函数输出:队头结点地址
========================================*/
LinkListNode *Delete_LkQueue(LinkQueue *lq) {
LinkListNode *s;
if(!Empty_LkQueue(lq)) { //队非空
s=lq->front->next;//s指向队头结点
if(s->next==NULL) //队中只有一个结点
lq->rear=lq->front;//队列置空
else lq->front->next=s->next;//摘下队头结点
return(s); //返回摘下的队头结点地址
}
return NULL; //队空时,返回NULL
}
问题:内存泄漏。
6.销毁链队列
为防止内存泄漏,要做队列的销毁处理。
/*======================================
函数功能:链队列的销毁
函数输入:队列起始地址
函数输出:无
========================================*/
void Destory_LkQueue(LinkQueue *lq)
{
LinkListNode *s;
while(!Empty_LkQueue(lq))
{
s=Delete_LkQueue(lq);
free(s;)
}
free(lq->front);
lq->front=NULL;
lq->rear=NULL;
}