利用C++搭建的循環順序隊列

利用C++搭建的循環順序隊列

在操作系統中的作業調度中有一個比較典型的調度策略,就是先來先服務的策略。當多個作業請求需要進行系統執行調用時,先提出服務請求的作業會被率先執行,後提出服務請求的會按照提出請求的順序“依次排隊”,等候後續的執行。其實這一排隊策略就可以藉助隊列來予以實現。

1.隊列的簡要概述

隊列一種限定存取位置的線性表,操作方式爲:在表的一段輸入,在表的另一端刪除與取出。允許插入的一段叫做隊尾(rear),允許刪除和取出的一端叫做隊頭(frout)。具體的操作形式,如下圖所示:

圖1

這個操作是不是讓大家想到了去火車站買票的操作。隊列最大的特徵就是:先進先出FIFO(First In First Out)。
隊列的存儲方式有兩種:一種是基於數組的存儲方式,即順序隊列;另一種是基於鏈表的存儲方式。本文是利用C++搭建的順序隊列。

2.搭建思路

2.1隊列基本的操作—插入與刪除/讀取

隊列的插入與刪除代表了隊列的基本內容,也是隊列的核心內容。隊列的插入與刪除/讀取的操作如下圖示:

圖2

從圖中可以看出:

1.) 隊列剛建立時,首先需要進行初始化,令front=rear=0。當加入一個新元素,將元素添加到rear指向的位置,並讓rear加1上移,即指向下一元素應當指向的位置。當刪除/讀取隊內某一元素時,將front指向的位置上移即可。
2. )如果front==rear,則表示該隊列爲空,如上圖所示的空隊以及C出隊(空隊)所示。
3. )從上圖所示D入隊的rear=Maxsize時,表示隊列“已滿”,如果再加入新元素就會產生“溢出”。但是我們從圖上可以看出,在隊列前端還有一定的存儲空間。,那我們如何讓前端的空間合理的利用起來呢?問題的解答其實就是如何將數組的前端與後端連接起來,形成一個完整的環呢?前人很機智的想到了除法取餘運算:
隊頭指針進1:front=(front+1)%Maxsize;
隊尾指針進1:rear=(rear+1)%Maxsize;
取餘運算可以當進行元素的插入與刪除/讀取操作時,當指針加至Maxsize-1時,利用%運算可以直接前進到數組的0號位置,對隊內的存儲空間充分利用。

2.2隊列基本操作的討論

藉助2.1的基本操作,我們可以構建出一個循環隊列,那在進行基本操作過程中,還需要什麼值得注意的呢?

1.)循環隊列的刪除/讀取元素速度大於存入的速度,隊頭指針(front)快速追上隊尾指針(rear),即front=rear時,該隊列爲空隊列。
2.)循環隊列的存入速度大於刪除/讀取元素的速度,隊尾指針(rear)很快會追上隊頭指針(front),也會出現front=rear,但這樣就會出現與空隊列一樣的判斷條件,這樣就造成了隊空條件與隊滿條件的混淆。爲了區分這個判斷條件,我們這裏有2個辦法:

方法1:判斷條件變爲:(rear+1)%Maxsize==front。也就是,讓rear指到front的前一位置就認爲隊已滿。也因此在該判斷條件下,隊滿情形實際空出了一個元素位置,也就是在循環隊列中最多存放Maxsize-1個元素。(本文所提供的代碼就是採用的是該判斷方法)
方法2:附加一個標誌位FLAG,該標誌位記錄該隊列最近一次操作類型,如果最近執行的進隊操作,即插入操作時,FLAG=1。當執行的是出隊操作,即刪除/讀取操作時,FLAG=0。當出現front=rear時,判斷FLAG的值,即可判斷隊列已滿還是隊列爲空。(注:使用加標誌位的方法時,當隊列使用十分頻繁,無疑會增加程序運行時間,故該方式謹慎使用。)

3.代碼

下列代碼就是根據上述思路所搭建的,供大家參考。

#include<iostream>

using namespace std;
/************************隊列結構定義***************************/
template<typename Datatype> class Queue
{
public:
	Queue(int size)
	{
		Maxsize = size;   //初始化最大容量
		//初始化隊首、隊尾、和元素數位0
		Frout = 0;       
		Rear = 0;
		count = 0;
		Elements = new Datatype[size];      //分配空間
		//如果空間分配失敗,則進行退出
		if (Elements==NULL)
		{
			cout << "空間分配失敗"<< endl;
			exit(1);
		}
	}
	~Queue()
	{
		delete [] Elements;
	}

	//入隊操作
	bool insert(Datatype data);
	//出隊操作
	Datatype delElement();
private:
	int count;             //隊列的個數
	int Maxsize;           //隊列的最大元素
	int Frout;             //隊首
	int Rear;              //隊尾
	Datatype *Elements;    //數據指針
};
/**************************入隊操作*************************/
template<typename Datatype>
bool Queue<Datatype>::insert(Datatype data)
{
	if (((Rear+1)%Maxsize)==Frout)                     //判斷是否隊列已滿
	{
		cout << "當前隊列已滿" << endl;
		return false;
	}
	Elements[Rear] = data;                           //將數據插入隊尾
	Rear = (Rear + 1)%Maxsize;  
	count++;                                         //元素數+1
}
/**************************出隊操作*************************/
template<typename Datatype>
Datatype Queue<Datatype>::delElement()
{
	if (Rear== Frout)                                 //判斷當前是否爲隊空
	{
		cout << "當前隊列爲空隊列" << endl;
		exit(1);
	}
	Datatype Data = Elements[Frout];                   //去除隊首元素
	Frout = (Frout + 1)%Maxsize;                       //設置新的隊首位置,爲節省空間,採用取模法
	count--;                                           //隊內元素減1
	return Data;
}
/**************************主函數*************************/
int main()
{
	//輸入構建隊列的長度
	cout << "輸入構建隊列的長度" << endl;
	int Queue_Number;
	cin >> Queue_Number;
	Queue<int> queue(Queue_Number);                     //初始化循環隊列
	for (int i = 0; i < (Queue_Number-1); i++)
	{
		queue.insert(i*10);
	}
	queue.insert(100);
	cout << "******************構建的隊列依次取出爲******************" << endl;
	for (int i = 0; i < (Queue_Number - 1); i++)
	{
		cout<<queue.delElement()<<"   ";
	}
	cout << ""<<endl;
	cout << "********************************************************" << endl;
	cout << queue.delElement() << "   ";
	return 0;
}

上述程序我已經運行過了,我認爲沒有什麼問題。如果大家在參考的過程中,遇到什麼問題,也希望大家相互交流。

參考文獻:
1.數據結構——殷人昆。
2.妙趣橫生的算法——胡浩。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章