【数据结构 9】优先队列及其Java实现

【数据结构 1】顺序表及其Java实现
【数据结构 2】单向链表及其Java实现
【数据结构 3】双向链表及其Java实现
【数据结构 4】栈及其Java实现
【数据结构 5】队列及其Java实现
【数据结构 6】符号表及其Java实现(使用链表实现)
【数据结构 7】二叉查找树及其Java实现
【数据结构 8】并查集及其Java实现
【数据结构 9】优先队列及其Java实现

未完待续…】不定期更新,内容总结整理不易,欢迎点赞关注博主!感谢!


优先队列

  • 一、什么是优先队列
  • 二、最大优先队列
    • 2.1 最大优先队列API设计
    • 2.2 最大优先队列代码实现
  • 三、最小优先队列
    • 3.1 最小优先队列API设计
    • 3.2 最小优先队列代码实现

一、什么是优先队列

  • 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值,例如使用一个队列保存计算机的任务,一般情况下计算机的任务都是有优先级的,我们需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,我们就可以使用一种特殊的队列来完成这种需求,优先队列。

  • 优先队列按照其作用不同,可以分为以下两种:
    最大优先队列: 可以获取并删除队列中最大的值
    最小优先队列: 可以获取并删除队列中最小的值

二、最大优先队列

  • 前面的文章介绍过,堆这种结构是可以方便的删除最大的值,所以,可以基于堆区实现最大优先队列。

2.1 最大优先队列API设计

类名 MaxPriorityQueue< T >
构造方法 MaxPriorityQueue(int capacity):创建容量为capacity的MaxPriorityQueue对象
成员方法1 1.private boolean less(int i,int j):判断堆中索引i处的元素是否小于索引j处的元素
成员方法2 2.private void exch(int i,int j):交换堆中i索引和j索引处的值
成员方法3 3.public T delMax():删除队列中最大的元素,并返回这个最大元素
成员方法4 4.public void insert(T t):往队列中插入一个元素
成员方法5 5.private void swim(int k):使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
成员方法6 6.private void sink(int k):使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
成员方法7 7.public int size():获取队列中元素的个数
成员方法8 8.public boolean isEmpty():判断队列是否为空
成员变量1 1.private T[] imtes : 用来存储元素的数组
成员变量2 2.private int N:记录堆中元素的个数

2.2 最大优先队列代码实现

// 最大优先队列代码
public class MaxPriorityQueue<T extends Comparable<T>> {
	//存储堆中的元素
	private T[] items;
	//记录堆中元素的个数
	private int N;

	public MaxPriorityQueue(int capacity) {
		items = (T[]) new Comparable[capacity+1];
		N = 0;
	}

	//获取队列中元素的个数
	public int size() {
		return N;
	}

	//判断队列是否为空
	public boolean isEmpty() {
		return N == 0;
	}
	
	//判断堆中索引i处的元素是否小于索引j处的元素
	private boolean less(int i, int j) {
		return items[i].compareTo(items[j]) < 0;
	}

	//交换堆中i索引和j索引处的值
	private void exch(int i, int j) {
		T tmp = items[i];
		items[i] = items[j];
		items[j] = tmp;
	}
	
	//往堆中插入一个元素
	public void insert(T t) {
		items[++N] = t;
		swim(N);
	}

	//删除堆中最大的元素,并返回这个最大元素
	public T delMax() {
		T max = items[1];
		//交换索引1处和索引N处的值
		exch(1, N);
		//删除最后位置上的元素
		items[N] = null;
		N--;//个数-1
		sink(1);
		return max;
	}

	//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
	private void swim(int k) {
		//如果已经到了根结点,就不需要循环了
		while (k > 1) {
			//比较当前结点和其父结点
			if (less(k / 2, k)) {
				//父结点小于当前结点,需要交换
				exch(k / 2, k);
			}
			k = k / 2;
		}
	}

	//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
	private void sink(int k) {
		//如果当前已经是最底层了,就不需要循环了
		while (2 * k <= N) {
			//找到子结点中的较大者
			int max = 2 * k;
			if (2 * k + 1 <= N) {//存在右子结点
				if (less(2 * k, 2 * k + 1)) {
					max = 2 * k + 1;
				}
			}
			//比较当前结点和子结点中的较大者,如果当前结点不小,则结束循环
			if (!less(k, max)) {
				break;
			}
			//当前结点小,则交换,
			exch(k, max);
			k = max;
		}
	}
}

三、最小优先队列

  • 最小优先队列实现起来也比较简单,同样也可以基于堆来完成最小优先队列。
  • 前文介绍堆的时候,堆中存放数据元素的数组要满足都满足如下特性
    1. 最大的元素放在数组的索引1处。
    2. 每个结点的数据总是大于等于它的两个子结点的数据。

【数据结构 9】优先队列及其Java实现_第1张图片

  • 上述的堆称为最大堆,可以用相反的思想实现最小堆,让堆中存放数据元素的数组满足如下特性
    1. 最小的元素放在数组的索引1处。
    2. 每个结点的数据总是小于等于它的两个子结点的数据。

【数据结构 9】优先队列及其Java实现_第2张图片
这样我们就能快速的访问到堆中最小的数据。

3.1 最小优先队列API设计

类名 MinPriorityQueue< T >
构造方法 MinPriorityQueue(int capacity):创建容量为capacity的MinPriorityQueue对象
成员方法1 1.private boolean less(int i,int j):判断堆中索引i处的元素是否小于索引j处的元素
成员方法2 2.private void exch(int i,int j):交换堆中i索引和j索引处的值
成员方法3 3.public T delMin():删除队列中最小的元素,并返回这个最小元素
成员方法4 4.public void insert(T t):往队列中插入一个元素
成员方法5 5.private void swim(int k):使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
成员方法6 6.private void sink(int k):使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
成员方法7 7.public int size():获取队列中元素的个数
成员方法8 8.public boolean isEmpty():判断队列是否为空
成员变量1 1.private T[] imtes : 用来存储元素的数组
成员变量2 2.private int N:记录堆中元素的个数

3.2 最小优先队列代码实现

// 最小优先队列代码
public class MinPriorityQueue<T extends Comparable<T>> {
	//存储堆中的元素
	private T[] items;
	//记录堆中元素的个数
	private int N;

	public MinPriorityQueue(int capacity) {
		items = (T[]) new Comparable[capacity+1];
		N = 0;
	}
	
	//获取队列中元素的个数
	public int size() {
		return N;
	}

	//判断队列是否为空
	public boolean isEmpty() {
		return N == 0;
	}

	//判断堆中索引i处的元素是否小于索引j处的元素
	private boolean less(int i, int j) {
		return items[i].compareTo(items[j]) < 0;
	}

	//交换堆中i索引和j索引处的值
	private void exch(int i, int j) {
		T tmp = items[i];
		items[i] = items[j];
		items[j] = tmp;
	}

	//往堆中插入一个元素
	public void insert(T t) {
		items[++N] = t;
		swim(N);
	}

	//删除堆中最小的元素,并返回这个最小元素
	public T delMin() {
		//索引1处的值是最小值
		T min = items[1];
		//交换索引1处和索引N处的值
		exch(1, N);
		//删除索引N处的值
		items[N] = null;
		//数据元素-1
		N--;
		//对索引1处的值做下沉,使堆重新有序
		sink(1);
		//返回被删除的值
		return min;
	}

	//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
	private void swim(int k) {
		//如果没有父结点,则不再上浮
		while (k > 1) {
			//如果当前结点比父结点小,则交换
			if (less(k, k / 2)) {
				exch(k, k / 2);
			}
			k = k / 2;
		}
	}
	
	//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
	private void sink(int k) {
		//如果没有子结点,则不再下沉
		while (2 * k <= N) {
			//找出子结点中的较小值的索引
			int min = 2 * k;
			if (2 * k + 1 <= N && less(2 * k + 1, 2 * k)) {
				min = 2 * k + 1;
			}
			//如果当前结点小于子结点中的较小值,则结束循环
			if (less(k, min)) {
				break;
			}
			//当前结点大,交换
			exch(min, k);
			k = min;
		}
	}
}

你可能感兴趣的:(数据结构与算法,数据结构,算法,Java,优先队列)