隊列:只允許在一端進行插入,在另一端進行刪除的線性表
鏈隊列:使用鏈表實現的隊列,具有隊頭指針和隊尾指針,指示隊列元素所在的位置
鏈隊列特性:
●只能隊尾插入元素,在隊頭刪除元素
●先進先出(First In First Out)的線性表,先進入的元素出隊,後進入的元素才能出隊
隊列示意圖:
空鏈隊列:
鏈隊的入棧操作:
鏈隊的出棧操作:
————————紙上得來終覺淺,絕知此事要躬行————————
話不多說,把代碼開起來,這樣晦澀的概念纔不會顯得蒼白無力!!!
#include<stdio.h>
#include<malloc.h>
#include<assert.h>//斷言
typedef int ElemType;//定義元素類型爲int型
/*鏈隊的結點類型*/
typedef struct QueueNode
{
ElemType data;
struct QueueNode *next;
}QueueNode,*PNode;
/*定義鏈隊結構*/
typedef struct LinkQueue
{
PNode front;//隊頭指針指向頭結點
PNode tail;//隊尾指針
}LinkQueue;
/*初始化鏈隊*/
void InitQueue(LinkQueue *Q)
{
//創建頭結點
QueueNode *s=(QueueNode *)malloc(sizeof(QueueNode));
assert(s!=NULL);
Q->front=Q->tail=s;//隊頭指針和隊尾指針都指向新結點
Q->tail->next=NULL;//隊尾結點的指針域置空
}
/*入隊*/
void EnQueue(LinkQueue *Q,ElemType x)
{
//隊尾指針的next指向新創建的結點(新結點進行尾插)
//更改尾指針tail的指向
QueueNode *s=(QueueNode *)malloc(sizeof(QueueNode));
assert(s!=NULL);
s->data=x;
s->next=NULL;//新結點的指針域爲空
Q->tail->next=s;//尾結點的指針域保存新結點的地址
Q->tail=s;//尾指針指向新結點
}
/*展示鏈隊元素*/
void ShowQueue(LinkQueue *Q)
{
QueueNode *p=Q->front->next;//指針p指向頭結點後第一個有效結點
printf("Front:>");
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;//指針p指向下一個有效結點
}
printf("<:Tail\n");
}
/*出隊*/
void DenQueue(LinkQueue *Q)
{
//出隊相當於頭部刪除結點的過程:頭結點的next指向第一個有效結點的後繼,然後釋放第一個有效結點
//注意:如果刪除隊尾結點,需要將隊尾指針tail再次指向頭結點
if(Q->front==Q->tail)//空隊列
return;
QueueNode *p=Q->front->next;//指針p指向頭結點後第一個有效結點
Q->front->next=p->next;//頭結點的指針域保存第二個有效結點的地址
free(p);//釋放第一個有效結點
if(p==Q->tail)//此時刪除最後一個結點(尾結點)
Q->tail=Q->front;//隊尾指針指向頭結點
}
/*取鏈隊頭元素*/
void GetHead(LinkQueue *Q,ElemType *v)//用指針v帶回鏈隊頭元素
{
if(Q->front==Q->tail)//空隊列
return;
QueueNode *p=Q->front->next;//指針p指向頭結點後第一個有效結點
*v=p->data;//p->data等價於Q->front->next->data
}
/*求鏈隊長度*/
int Length(LinkQueue *Q)
{
int len=0;//初始化長度爲0
QueueNode *p=Q->front->next;//指針p指向頭結點後第一個有效結點
while(p!=NULL)//只有結點不爲空,len增加
{
len++;
p=p->next;
}
return len;
}
/*清除鏈隊*/
void ClearQueue(LinkQueue *Q)//除頭結點外,對所有結點進行清除
{
if(Q->front==Q->tail)//如果頭指針與尾指針指向相同,則鏈隊爲空
return;//無需清除
QueueNode *p=Q->front->next;//指針p指向頭結點後第一個有效結點
while(p!=NULL)
{
Q->front->next=p->next;//頭結點的指針域保存第二個有效結點的地址
free(p);//釋放第一個有效結點
p=Q->front->next;//指針p重新指向頭結點後第一個有效結點
}
//釋放完成後,對尾部指針進行修改
Q->tail=Q->front;//隊尾指針指向頭結點
}
/*銷燬鏈隊*/
void DestroyQueue(LinkQueue *Q)//清除的前提下釋放頭結點實現銷燬
{
ClearQueue(Q);
free(Q->front);//釋放頭結點
Q->front=Q->tail=NULL;//隊頭和隊尾指針都賦空,預防野指針
}
void main()
{
LinkQueue Q;
ElemType e;//鏈隊頭元素
InitQueue(&Q);
for(int i=1;i<=10;++i)
{
EnQueue(&Q,i);
}
ShowQueue(&Q);
printf("出隊\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("鏈隊頭元素爲:%d\n",e);
ShowQueue(&Q);
printf("鏈隊的長度爲:%d\n",Length(&Q));
printf("\n");
printf("出隊\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("鏈隊頭元素爲:%d\n",e);
ShowQueue(&Q);
printf("鏈隊的長度爲:%d\n",Length(&Q));
printf("\n");
printf("出隊\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("鏈隊頭元素爲:%d\n",e);
ShowQueue(&Q);
printf("鏈隊的長度爲:%d\n",Length(&Q));
printf("\n");
printf("出隊\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("鏈隊頭元素爲:%d\n",e);
ShowQueue(&Q);
printf("鏈隊的長度爲:%d\n",Length(&Q));
printf("\n");
ClearQueue(&Q);
DestroyQueue(&Q);
}
運行結果: