今天看圖的廣度優先遍歷的時候,發現用到了隊列,補一下循環隊列的知識,參考《大話數據結構》的P116~117,自己寫了一個簡單的測試例子便於理解。
首先需要理解以下三條公式。
front是隊頭元素的下標,rear是隊尾元素后一位的下標。(書上用頭指針和尾指針,front和rear並不是指針,個人覺得不太好)
1、隊列空的條件
顯然front==rear
注意:如果隊列不保留任何元素空間
滿足front==rear的情況下,可能是隊列空,也可能是隊列滿。所以為了方便,本文討論的是采用保留一個元素空間的方法。(也可以采用設置標志變量的方法)
2、隊列滿的條件
隊列滿只有這兩種情況,所以隊列滿的條件是:
(rear+1)%QueueSize==front
3、隊列長度計算公式
同時考慮這兩種情況,隊列計算公式是:
rear-front+MAXSIZE)%MAXSIZE
MAXSIZE是隊列長度(包括那個保留的元素空間)
下面舉個簡單的例子,實現循環隊列的創建,入隊和出隊操作。
代碼和解釋如下(VS2012測試通過):
1 #include <iostream>
2 #include <string>
3 using namespace std; 4
5 #define MAXSIZE 5
6
7 //循環隊列的順序存儲結構
8 typedef struct
9 { 10 char data[MAXSIZE];//隊列,用數組形式表示,這里假設最多只有4個元素 11 //保留一個元素空間,否則front==rear,是空隊列還是滿隊列不容易判斷
12 int front;//頭序號,第一個元素的下標
13 int rear;//尾序號,最后一個元素的下標
14 }SqQueue; 15
16 //循環隊列的初始化,返回指向循環隊列的地址
17 SqQueue *InitQueue(SqQueue *Q) 18 { 19 Q=new SqQueue; 20 Q->front=0; 21 Q->rear=0;//初始化為空隊列(front==rear為空隊列)
22 return Q; 23 } 24
25 //求循環隊列的長度,返回循環隊列的當前長度
26 int QueueLength(SqQueue *Q) 27 { 28 return (Q->rear-Q->front+MAXSIZE)%MAXSIZE; 29 } 30
31 //循環隊列的入隊列操作
32 void EnQueue(SqQueue *Q,char e) 33 { 34 if((Q->rear+1)%MAXSIZE==Q->front)//判斷循環隊列是否滿
35 { 36 cout<<"error"<<" "; 37 return; 38 } 39 Q->data[Q->rear]=e;//將元素e插入隊尾
40 Q->rear=(Q->rear+1)%MAXSIZE;//尾序號rear加1,若到最后轉向頭部
41 cout<<"ok"<<" "; 42 return; 43 } 44
45 //循環隊列的出隊列操作
46 char DeQueue(SqQueue *Q) 47 { 48 char e; 49 if(Q->front==Q->rear)//如果隊列是否空
50 { 51 cout<<"error"<<" "; 52 return 0;//返回0表示隊列空,沒有出隊元素
53 } 54 e=Q->data[Q->front]; 55 Q->front=(Q->front+1)%MAXSIZE;//頭序號front加1,若到最后轉向頭部
56 cout<<"ok"<<" "<<e<<endl; 57 return e; 58 } 59
60 int main(void) 61 { 62 SqQueue *s=NULL; 63
64 //初始化一個空隊列s
65 s=InitQueue(s); 66
67 //插入元素,並返回當前隊列長度
68 EnQueue(s,'A');//插入A
69 cout<<s->data[0]<<" ";//提示隊尾是否插入A(因為初始化時rear=0,所以從下標為0的地方開始插入)
70 cout<<QueueLength(s)<<endl;//輸出當前長度1
71
72 EnQueue(s,'B');//插入B
73 cout<<s->data[1]<<" ";//提示隊尾是否插入B
74 cout<<QueueLength(s)<<endl;//輸出當前長度2
75
76 EnQueue(s,'C');//插入C
77 cout<<s->data[2]<<" ";//提示隊尾是否插入C成功
78 cout<<QueueLength(s)<<endl;//輸出當前長度3
79
80 EnQueue(s,'D');//插入D
81 cout<<s->data[3]<<" ";//提示隊尾是否插入D成功
82 cout<<QueueLength(s)<<endl;//輸出當前長度4
83
84 EnQueue(s,'E');//插入E,輸出error,說明插入失敗
85 cout<<QueueLength(s)<<endl;//輸出當前長度4,說明已經滿了不能再插入 86
87 //出隊
88 DeQueue(s);//輸出A
89 DeQueue(s);//輸出B 90
91 //再插入元素,理解隊列的循環
92 EnQueue(s,'E');//插入E
93 cout<<s->data[4]<<" "<<s->rear<<endl;//提示隊尾是否插入E成功,這時候rear挪到下標0的地方了
94 EnQueue(s,'F');//插入F
95 cout<<s->data[0]<<" "<<s->rear<<endl;//提示隊尾是否插入F成功,這時候rear挪到下標1的地方了
96 EnQueue(s,'G');//插入G,輸出error,說明插入失敗
97 cout<<QueueLength(s)<<endl;//輸出當前長度4,說明已經滿了不能再插入
98 }
運行結果: