隊列的三種實現方式


簡介

三種實現方式,其實就是指,循環隊列如何實現判空判滿,區別就在這一塊,原因是,如果不修改普通隊列,會出現二義性,因為空滿的狀態其實是同一種狀態。 下面介紹這三種方式。

方式一

通過空出一個位置,解決判空/滿的沖突,這是第一次介紹循環隊列,附上全部實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

template<class ,int MAXSIZE> //定義類模板CirQueue
class CirQueue
{
public:
CirQueue();
~CirQueue();

void EnQueue(T x);//入棧操作,將元素x入棧
T DeQueue(); //出棧操作,將隊頭元素出隊
T GetQueue(); //取隊頭元素
bool IsFull(); //判斷隊列是否為滿
bool Empty(); //判斷隊列是否為空
private:
T data[MAXSIZE]; //元素域
int front,rear; //隊頭和隊尾的指針
};

隊列,其實很簡單,他是只允許在一端進行插入,而在另一端進行刪除的運算受限的線性表,所以比較容易掌握。

下面附上具體函數的實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
* 無參構造函數,
*/
template<class ,int MAXSIZE>
CirQueue<T,MAXSIZE>::CirQueue()
{
front=rear=0;
}
/*
* 入隊函數,因為要求在隊尾增加元素,
* 所以,如果線性表未滿
* 讓尾指針向后移,為了不出現假溢出,充分利用空間,
* 所以有取模操作,當到達尾部最大值,則回到0,重新開始。
* 插入時先移動指針,后插入
*/
template <class ,int QueueSize>
void CirQueue<T,QueueSize>::EnQueue(T x)
{
if(IsFull()) //判滿
{
cout<<"上溢"<<endl;
return;
}
rear = (rear+1) % QueueSize; //隊尾指針在循環意義上加1
data[rear] = x; //在隊尾處插入元素
}
/*
* 出隊函數,在隊頭彈出元素,
* 所以,如果線性表不空
* 頭指針后移,指向當前的第一個元素,如果當前頭指針指向最后一個格子
* 那么進行取模操作,回到0位置。
*/
template <class ,int QueueSize>
CirQueue<T,QueueSize>::DeQueue()
{

if(Empty()) //判空
{
cerr<<"下溢"<<endl;
}
front = (front+1) % QueueSize; //隊頭指針在循環意義上加1
return data[front]; //讀取並返回出隊前的隊頭元素
}
/*
* 取隊頭元素,不出隊伍。
*/
template <class T,int QueueSize>
T CirQueue<T,QueueSize>::GetQueue()
{
if(Empty()) //判空
{
cerr<<"下溢"<<endl;
exit(0);
}
int i = (front+1) % QueueSize; //隊頭指針在循環意義上加1
return data[i];
}
/*
* 判空函數
* 如果當兩指針重合,隊列為空
*/
template <class T,int QueueSize>
bool CirQueue<T,QueueSize>::Empty()
{
return front == rear;
}
/*
* 判滿函數
* 如果尾指針邏輯后一格為頭指針
* 表示空間滿
*/
template <class T,int QueueSize>
bool CirQueue<T,QueueSize>::IsFull()
{
if( (rear+1) % QueueSize == front)
return true;
else
return false;
}

下面對這個函數做個基本的測試。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
CirQueue<int,5> Q;
//塞滿整個隊列
cout<<"塞滿隊列。。。"<<endl;
for (int i=0;;i++)
{
if (!Q.IsFull())
{
Q.EnQueue(pow(2,i));
}
else
break;
}
//測試訪問頭元素
cout<<"取出頭元素:";
cout<<Q.GetQueue()<<endl;

//依次出列
cout<<"依次出列:";
while (!Q.Empty())
{
cout<&l 大專欄  隊列的三種實現方式t;Q.DeQueue()<<" ";//因為這個函數寫了返回值。。
}
return 0;
}

測試結果如圖:
此處輸入圖片的描述

方式二

為了不浪費一個元素空間,加上一個布爾變量,在入隊操作時候把他變為true,如果flag為真,並且front==rear,那么表明隊伍滿了;在出隊的時候,把他設為false,如果最后一個操作為出隊,那么又遇到了front==rear,那么表明,這個時候隊伍是空的。代碼實現如下:

1
2
3
//與上一方式,在這邊,僅加了一個bool的控制量
private
bool flag;

下面列出實現時候,與第一種的區別之處:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
template<class T,int MAXSIZE>
CirQueue<T,MAXSIZE>::~CirQueue()
{
}
/*
* 無參構造函數,設置flag為假,保證,初始判斷讓程序判斷為空
*/
template<class T,int MAXSIZE>
CirQueue<T,MAXSIZE>::CirQueue()
{
front=rear=0;
flag=false;
}
/*
* 入隊函數,因為要求在隊尾增加元素,
* 所以,如果線性表未滿
* 讓尾指針向后移,為了不出現假溢出,充分利用空間,
* 所以有取模操作,當到達尾部最大值,則回到0,重新開始。
* 插入時先移動指針,后插入
* 同時,讓flag置為true
*/
template <class T,int QueueSize>
void CirQueue<T,QueueSize>::EnQueue(T x)
{
if(IsFull()) //判滿
{
cout<<"上溢"<<endl;
return;
}
rear = (rear+1) % QueueSize; //隊尾指針在循環意義上加1
data[rear] = x; //在隊尾處插入元素
flag=true;
}
/*
* 出隊函數,在隊頭彈出元素,
* 所以,如果線性表不空
* 頭指針后移,指向當前的第一個元素,如果當前頭指針指向最后一個格子,
* 那么進行取模操作,回到0位置。
* 所以隊頭所指的空間是么有元素的。
* 同時置flag為false
*/
template <class T,int QueueSize>
T CirQueue<T,QueueSize>::DeQueue()
{

if(Empty()) //判空
{
cerr<<"下溢"<<endl;
}
front = (front+1) % QueueSize; //隊頭指針在循環意義上加1
flag=false;
return data[front]; //讀取並返回出隊前的隊頭元素
}
/*
* 取隊頭元素,不出隊伍。
*/
template <class T,int QueueSize>
T CirQueue<T,QueueSize>::GetQueue()
{
if(Empty()) //判空
{
cerr<<"下溢"<<endl;
exit(0);
}
int i = (front+1) % QueueSize; //隊頭指針在循環意義上加1
return data[i];
}
/*
* 判空函數
* 如果當兩指針重合,隊列為空
*/
template <class T,int QueueSize>
bool CirQueue<T,QueueSize>::Empty()
{
if ( flag==false && front == rear )
return true;
else
return false;
}
/*
* 判滿函數
* 如果尾指針邏輯后一格為頭指針
* 表示空間滿
*/
template <class T,int QueueSize>
bool CirQueue<T,QueueSize>::IsFull()
{
if ( flag==true && front == rear )
return true;
else
return false;
}

測試函數不做變動,測試結果如下:
此處輸入圖片的描述

方式三

用計數器來存儲個數,當計數器等於0的時候,空;當計數器等於MAXSIZE的時候,滿!
程序很簡單,不多說。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* 判空函數
*/
template <class T,int QueueSize>
bool CirQueue<T,QueueSize>::Empty()
{
return count==0;
}
/*
* 判滿函數
*/
template <class T,int QueueSize>
bool CirQueue<T,QueueSize>::IsFull()
{
return count==QueueSize;
}

測試結果和方法二同。

總結:

三種方法

  • 空出一個格子
  • 加上flag判定
  • 加上計數器

還要注意一點:為了實現循環計數,要掌握下面的語句

  • raer=(rear+1)%MAXSIZE
  • front=(front+1)%MAXSIZE


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM