数据结构实现 6.2:优先队列_基于最大二叉堆实现(C++版)

1. 概念及基本框架

队列 是一种现实中很常见的数据结构,但有时候队列排序不仅仅依靠入队时间来决定,而是不同的元素有不同的优先级。显然,通过 6.1 中的 最大二叉堆 可以很容易实现 优先队列

优先队列

优先队列队列 的一种,所以有队列的基本特性:
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 PriorityQueue{
	...
private:
	MaxHeap<T> heap;
};

同样,这里为了避免重复设计就可以兼容更多数据类型,引入了 泛型 ,即 模板 的概念。(模板的关键字是 classtypename
这里的 heap 表示一个 最大二叉堆 ,同样,为了保护数据,变量设置为 private
注:这里没有显式的给出构造函数,因为子类中除了最大二叉堆对象之外没有特别需要初始化的东西。编译器会默认先调用 最大二叉堆 类(即父类)的构造函数,再去调用 优先队列 类(即子类)的构造函数。
实现了前面的程序之后,接下来就是一个队列的增、删、查以及一些其他基本操作,接下来利用代码去实现。

2. 基本操作程序实现

2.1 入队操作

template <class T>
class PriorityQueue{
public:
	...
	//入队操作
	void enqueue(T num){
		heap.add(num);
	}
	...
};

2.2 出队操作

template <class T>
class PriorityQueue{
public:
	...
	//出队操作
	void dequeue(){
		heap.extractMax();
	}
	...
};

2.3 查找操作

template <class T>
class PriorityQueue{
public:
	...
	//获得队首元素
	T front(){
		return heap.findMax();
	}
	...
};

2.4 其他操作

优先队列还有一些其他的操作,包括 队列大小 等的查询等操作。

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

3. 算法复杂度分析

因为这里直接调用的最大二叉堆的接口函数,所以基本操作的时间复杂度和最大二叉堆操作的时间复杂度相同。

3.1 入队操作

函数 最坏复杂度 平均复杂度
enqueue O(logn) O(logn)

3.2 出队操作

函数 最坏复杂度 平均复杂度
dequeue O(logn) O(logn)

3.3 查找操作

函数 最坏复杂度 平均复杂度
front O(1) O(1)

总体情况:

操作 时间复杂度
O(logn)
O(logn)
O(1)

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 __MAXHEAP_H__
#define __MAXHEAP_H__

#include "Array.h"

template <class T>
class MaxHeap{
public:
	int size(){
		return arr.size();
	}
	bool isEmpty(){
		return arr.isEmpty();
	}
	void add(T num){
		arr.addLast(num);
		siftUp(arr.size() - 1);
	}
	T findMax(){
		if (arr.size() == 0){
			cout << "二叉堆为空!" << endl;
			return NULL;
		}
		return arr.get(0);
	}
	T extractMax(){
		T res = findMax();
		swap(0, arr.size() - 1);
		arr.removeLast();
		siftDown(0);
		return res;
	}
private:
	int parent(int index){
		if (index <= 0 || index >= arr.size()){
			return NULL;
		}
		return (index - 1) / 2;
	}
	int leftChild(int index){
		return index * 2 + 1;
	}
	int rightChild(int index){
		return (index + 1) * 2;
	}
	void swap(int i, int j){
		if (i < 0 || i >= arr.size() || j < 0 || j >= arr.size()){
			return;
		}
		T t = arr.get(i);
		arr.set(i, arr.get(j));
		arr.set(j, t);
	}
	void siftUp(int index){
		while (index && arr.get(index) > arr.get(parent(index))){
			swap(index, parent(index));
			index = parent(index);
		}
	}
	void siftDown(int index){
		while (leftChild(index) < arr.size()){
			int left = leftChild(index);
			if (left + 1 < arr.size() && arr.get(left + 1) > arr.get(left)){
				left++;
			}
			if (arr.get(index) >= arr.get(left)){
				break;
			}
			swap(index, left);
			index = left;
		}
	}
private:
	Array<T> arr;
};

#endif

优先队列类 代码:

#ifndef __PRIORITYQUEUE_H__
#define __PRIORITYQUEUE_H__

#include "Queue.h"
#include "MaxHeap.h"

template <class T>
class PriorityQueue{
public:
	int size(){
		return heap.size();
	}
	bool isEmpty(){
		return heap.isEmpty();
	}
	void print(){
		if (heap.isEmpty()){
			return;
		}
		cout << "PriorityQueue: ";
		cout << "Size = " << heap.size() << endl;
		cout << "front [";
		cout << heap.findMax() << "...";
		cout << "] rear" << endl;
	}
	//入队操作
	void enqueue(T num){
		heap.add(num);
	}
	//出队操作
	void dequeue(){
		heap.extractMax();
	}
	//获得队首元素
	T front(){
		return heap.findMax();
	}
private:
	MaxHeap<T> heap;
};

#endif

猜你喜欢

转载自blog.csdn.net/qq_35481167/article/details/84072520