1. 程式人生 > >資料結構實現 6.3:優先佇列_基於動態陣列實現(C++版)

資料結構實現 6.3:優先佇列_基於動態陣列實現(C++版)

資料結構實現 6.3:優先佇列_基於動態陣列實現(C++版)

1. 概念及基本框架

6.2 中通過 最大二叉堆 實現了 優先佇列 ,這一節我們通過動態陣列來實現優先佇列。

優先佇列

優先佇列佇列 的一種,所以有佇列的基本特性:
1.佇列

隊頭隊尾 兩端。
2.入隊 操作只能從 隊尾 進行,出隊 操作只能從 隊頭 進行。
3.先 入隊 的先 出隊 ,即 先進先出(First In First Out),FIFO
還有一個隱含特性,佇列可以自行 擴容(縮容),而不需要使用者關心,很顯然,動態陣列已經滿足了這個要求。
首先使用一個由 純虛擬函式 構成的 抽象類 作為一個佇列介面,介面內定義一些佇列的基本操作。具體程式碼如下:

template <class T>
class Queue{
public:
	virtual int size() = 0;
	virtual bool isEmpty() =
0; virtual void print() = 0; //入隊操作 virtual void enqueue(T num) = 0; //出隊操作 virtual void dequeue() = 0; //獲得隊首元素 virtual T front() = 0; };

下面只需要通過繼承 抽象類,並且重寫 純虛擬函式 ,就可以完成 優先佇列 的實現。優先佇列類的框架如下:

template <class T>
class ArrayPriorityQueue{
...
private:
	Array<T> arr;
};

同樣,這裡為了避免重複設計就可以相容更多資料型別,引入了 泛型

,即 模板 的概念。(模板的關鍵字是 classtypename
這裡的 arr 表示一個 動態陣列 ,同樣,為了保護資料,變數設定為 private
注:這裡沒有顯式的給出建構函式,因為子類中除了動態陣列物件之外沒有特別需要初始化的東西。編譯器會預設先呼叫 動態陣列 類(即父類)的建構函式,再去呼叫 優先佇列 類(即子類)的建構函式。
實現了前面的程式之後,接下來就是一個佇列的增、刪、查以及一些其他基本操作,接下來利用程式碼去實現。

2. 基本操作程式實現

2.1 入隊操作

template <class T>
class ArrayPriorityQueue{
public:
	...
	//入隊操作
	void enqueue(T num){
		arr.addLast(num);
	}
	...
};

2.2 出隊操作

template <class T>
class ArrayPriorityQueue{
public:
	...
	//出隊操作
	void dequeue(){
		if (arr.isEmpty()){
			cout << "出隊失敗!" << endl;
			return;
		}
		arr.remove(findMax());
	}
	...
private:
	int findMax(){
		int index = 0;
		for (int i = 0; i < arr.size(); ++i){
			if (arr.get(i) > arr.get(index)){
				index = i;
			}
		}
		return index;
	}
	...
};

這裡利用了一次遍歷查詢最大元素。

2.3 查詢操作

template <class T>
class ArrayPriorityQueue{
public:
	...
	//獲得隊首元素
	T front(){
		return arr.get(findMax());
	}
private:
	int findMax(){
		int index = 0;
		for (int i = 0; i < arr.size(); ++i){
			if (arr.get(i) > arr.get(index)){
				index = i;
			}
		}
		return index;
	}
	...
};

這裡利用了一次遍歷查詢最大元素。

2.4 其他操作

優先佇列還有一些其他的操作,包括 佇列大小 等的查詢等操作。

template <class T>
class ArrayPriorityQueue{
public:
	int size(){
		return arr.size();
	}
	bool isEmpty(){
		return arr.isEmpty();
	}
	void print(){
		if (arr.isEmpty()){
			return;
		}
		cout << "ArrayPriorityQueue: ";
		cout << "Size = " << arr.size() << endl;
		cout << "front [";
		cout << arr.get(findMax()) << "...";
		cout << "] rear" << endl;
	}
	...
};

3. 演算法複雜度分析

這裡入隊使用直接插入,出隊時遍歷查詢的方法實現優先佇列。

3.1 入隊操作

函式 最壞複雜度 平均複雜度
enqueue O(1) O(1)

3.2 出隊操作

函式 最壞複雜度 平均複雜度
dequeue O(n) O(n/2) = O(n)

3.3 查詢操作

函式 最壞複雜度 平均複雜度
front O(n) O(n/2) = O(n)

總體情況:

操作 時間複雜度
O(1)
O(n)
O(n)

也可以採用入隊時遍歷放入適當位置,出隊出隊頭。

4. 完整程式碼

程式完整程式碼(這裡使用了標頭檔案的形式來實現類)如下:
優先佇列介面函式一覽:

函式宣告 函式型別 函式功能
int size() public 返回二叉堆的大小
bool isEmpty() public 返回優先佇列是否為空(空為true)
void print() public 列印輸出優先佇列隊頭
void enqueue(T) public 入隊元素到優先佇列
void dequeue() public 從優先佇列中出隊一個元素
T front() public 獲得優先佇列隊頭元素

抽象類 介面程式碼:

#ifndef __QUEUE_H__
#define __QUEUE_H__

template <class T>
class Queue{
public:
	virtual int size() = 0;
	virtual bool isEmpty() = 0;
	virtual void print() = 0;
	//入隊操作
	virtual void enqueue(T num) = 0;
	//出隊操作
	virtual void dequeue() = 0;
	//獲得隊首元素
	virtual T front() = 0;
};

#endif

這裡不再給出動態陣列程式碼。

優先佇列類 程式碼:

#ifndef __ARRAYPRIORITYQUEUE_H__
#define __ARRAYPRIORITYQUEUE_H__

#include "Queue.h"
#include "Array.h"

template <class T>
class ArrayPriorityQueue{
public:
	int size(){
		return arr.size();
	}
	bool isEmpty(){
		return arr.isEmpty();
	}
	void print(){
		if (arr.isEmpty()){
			return;
		}
		cout << "ArrayPriorityQueue: ";
		cout << "Size = " << arr.size() << endl;
		cout << "front [";
		cout << arr.get(findMax()) << "...";
		cout << "] rear" << endl;
	}
	//入隊操作
	void enqueue(T num){
		arr.addLast(num);
	}
	//出隊操作
	void dequeue(){
		if (arr.isEmpty()){
			cout << "出隊失敗!" << endl;
			return;
		}
		arr.remove(findMax());
	}
	//獲得隊首元素
	T front(){
		return arr.get(findMax());
	}
private:
	int findMax(){
		int index = 0;
		for (int i = 0; i < arr.size(); ++i){
			if (arr.get(i) > arr.get(index)){
				index = i;
			}
		}
		return index;
	}
private:
	Array<T> arr;
};

#endif