一、鏈隊列的基本結構
隊列的鏈式存儲結構,其實就是線性表的單鏈表,只不過它只能尾進頭出而已,我們把它簡稱為鏈隊列。
為了操作上的方便,我們將隊頭指針指向鏈隊列的頭結點,而隊尾指針指向終端結點。鏈隊列示意圖:
當隊列為空時,front和rear都指向頭結點。
二、鏈隊列結構體定義
鏈隊列結構體的定義,需要兩個步驟:
(1)鏈隊列節點的定義
/* QElemType類型根據實際情況而定,這里假設為int */
typedef int QElemType;
typedef struct QNode /* 結點結構 */
{
QElemType data;
struct QNode *next;
} QNode;
(2) LinkQueue的結構體定義。只要定義隊頭和隊尾指針即可。
typedef struct /* 隊列的鏈表結構 */
{
QNode *front; /* 隊頭、隊尾指針 */
QNode *rear;
} LinkQueue;
三、實現要點
1、初始化。
鏈隊列的初始化可以依據單鏈表的初始化,單鏈表的初始化是這樣的:
(1)首先產生頭結點(分配內存空間),並使L指向此頭結點:
L=(LinkList*)malloc(sizeof(Node));
(2)再將指針域置空:L->next=NULL;
因此,鏈隊列的初始化如下:
(1)產生頭結點 (LinkQueue)malloc(sizeof(LinkQueue)),然后讓隊頭指針(頭指
針)與隊尾指針都指向頭結點。
(2)置空頭結點 Q->front 的指針域 Q->front->next=NULL;
代碼如下:
/* 構造一個空隊列q */
LinkQueue *InitQueue(LinkQueue *q)
{
q->front = q->next =(QNode*)malloc(sizeof(QNode));
q->front->next = NULL;
return q;
}
2、入隊。入隊操作就是在鏈隊列的尾部插入結點。
如上圖,入隊操作步驟大致如(1)(2)所示。實現算法為:
(1)創建結點s,QNode p=(QNode)malloc(sizeof(QNode));
(2)給s的data域賦值e,指針域next賦值null。p->data=e;p->next=NULL; 目的
是讓它成為新的隊尾元素。
(3)前任隊尾元素呢?直接讓它的指針域指向p。Q->rear->next=p;
(4)把隊尾指針重新指向新任隊尾s。Q->rear=p;
3、出隊。出隊操作時,就是頭結點的后繼結點(隊頭)出隊,將頭結點的后繼改為它后面的結點,若鏈表除頭結點外只剩一個元素時,則需將rear指向頭結點。
一般情況下,鏈隊列的出隊圖示:
如果鏈隊列只剩下一個元素的時候,出隊則如下圖:
具體步驟:
(1)如圖中,要刪除掉a1結點,思路很簡單,就是讓頭結點Q->front的后繼next直接指向a2。但是a2如何標識呢?
(2)假設a1結點為p結點,那么a2就是p->next了。如何讓a1結點存到p呢?
(3)直接讓頭結點的后繼指向p就行,p=Q->front->next;
(4)假如隊尾已經是p結點的話(Q->rear==p),隊尾指針需要指向頭結點Q->rear=Q->front;
(5)最后把p free掉。
四、鏈隊列代碼實現
#include <iostream>
#include<stdlib.h>
using namespace std;
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode;
typedef struct
{
QNode *front;
QNode *rear;
}LinkQueue;
// 構造一個空隊列q
LinkQueue *InitQueue(LinkQueue *q)
{
q->front = q->rear =(QNode*)malloc(sizeof(QNode));
q->front->next = NULL;
return q;
}
// 元素入隊
LinkQueue *EnQueue(LinkQueue *q, QElemType e)
{
QNode *p = (QNode*)malloc(sizeof(QNode));//為插入節點分配空間
if(!p)
{//分配空間失敗
cout<<"插入節點內存分配失敗!"<<endl;
}
else
{ //建節點
p->data = e; //為插入節點數據域賦值
p->next = NULL;//為插入節點指針域賦值
//實現插入
q->rear->next = p;//插入到隊尾
q->rear = p;//隊尾指針重新指向新任隊尾
}
return q;
}
//元素出隊
LinkQueue *DeQueue(LinkQueue *q)
{
QNode *p;
if(q->front == q->rear)
{
cout<<"鏈隊列已空,不可再執行刪除操作!"<<endl;
}
else
{
p = q->front->next;//將欲刪除的隊頭結點暫存給p
QElemType e = p->data;//把隊頭數據賦給e
cout<<"delete: "<<e<<endl;
q->front->next = p->next;//刪除,將原隊頭結點的后繼p->next賦值給頭結點后繼
if(q->rear == p)
{//若隊頭就是隊尾,則刪除后將rear指向頭結點
cout<<"鏈隊列數據全部刪除完畢!"<<endl;
q->rear = q->front;
}
free(p);
}
return q;
}
//返回隊頭元素
void GetQHead(LinkQueue *q)
{
QNode *p;
if(q->front == q->rear)
{
cout<<"鏈隊列為空,無法返回隊頭數據"<<endl;
}
else
{
p = q->front->next;//隊頭
cout<<"隊頭元素:"<<p->data<<endl;
}
}
//求隊列長度
void QueueLength(LinkQueue *q)
{
int length = 0;
QNode *p;
p = q->front->next;//隊頭
while(p)
{
length++;
p = p->next;
}
cout<<"隊列長度:"<<length<<endl;
}
//打印。帶頭結點,真正存儲元素的位置從頭結點下一位置(隊頭)開始!!!
void PrintQueue(LinkQueue *q)
{
QNode *p;//隊頭
p = q->front->next;//頭結點的下一節點,即為隊頭!!!
while(p)
{//從隊頭開始,依次往后遍歷
cout<<p->data<<" ";
p = p->next;
}
cout<<endl;
}
int main()
{
LinkQueue *q = InitQueue(q);
EnQueue(q, 1);
PrintQueue(q);
EnQueue(q, 2);
PrintQueue(q);
EnQueue(q, 3);
PrintQueue(q);
EnQueue(q, 4);
PrintQueue(q);
GetQHead(q);
QueueLength(q);
cout<<"***************"<<endl;
DeQueue(q);
PrintQueue(q);
GetQHead(q);
DeQueue(q);
PrintQueue(q);
GetQHead(q);
DeQueue(q);
PrintQueue(q);
DeQueue(q);
PrintQueue(q);
QueueLength(q);
cout<<"***************"<<endl;
DeQueue(q);
cout<<"***************"<<endl;
return 0;
}
輸出結果:
1
1 2
1 2 3
1 2 3 4
隊頭元素:1
隊列長度:4
***************
delete: 1
2 3 4
隊頭元素:2
delete: 2
3 4
隊頭元素:3
delete: 3
4
delete: 4
鏈隊列數據全部刪除完畢!
隊列長度:0
***************
鏈隊列已空,不可再執行刪除操作!
***************
Process returned 0 (0x0) execution time : 0.053 s
Press any key to continue.