最大堆
堆概念
- 是一棵完全二叉树
- 父亲节点的优先级高于或低于左右孩子的优先级
完全二叉树
按照树的结构,从左到右依次排列
满二叉树
- 除叶子结点外所有的节点都有左右子树
- 叶子结点都在最后一层
- 第N层节点的个数:2^(N-1)
- 叶子结点个数:2^(h-1) h为高度
- 非叶子结点个数:2^(h-1) -1
- 总节点个数:2^h -1
最大堆概念
- 根节点索引为0,没有父亲节点
- 一个索引为 i 的节点的父亲节点的索引为:parent=i/(2-1) (根节点除外)
- 任意节点的左孩子索引为 left=2*(i-1)
- 任意节点的右孩子索引为 left=2*(i-1)+1
时间复杂度分析
- 上浮和下沉操作,最大交换次数为树的高度 h,时间复杂度为O(logn)
- 将一个元素插入到堆中,复杂度为O(logn),所以,将n个元素逐个插入到一个空堆中,算法复杂堆为O(nlogn)
- heapify(整理)的过程时间复杂度为O(n)
最大堆实现
public class MaxHeap<T extends Comparable<T>> {
private T[] data;
private int size;
public MaxHeap() {
this.data = (T[]) new Comparable[100];
this.size = 0;
}
public MaxHeap(T[] arr) {
this.data = Arrays.copyOf(arr, arr.length);
this.size = arr.length;
}
public boolean isEmpty() {
return this.size == 0;
}
public int getSize() {
return this.size;
}
public int getParentIndex(int index) {
if (index < 0) {
throw new IllegalArgumentException("index is error!");
} else if (index == 0) {
return -1;
} else {
return (index - 1) / 2;
}
}
private int getLeftChildIndex(int index) {
if (index < 0) {
throw new IllegalArgumentException("index is invalid!");
}
return 2 * index + 1;
}
public void add(T ele) {
data[size] = ele;
this.size++;
floatUp(size - 1);
}
private void floatUp(int i) {
int parentIndex = getParentIndex(i);
while (i > 0 && data[i].compareTo(data[parentIndex]) > 0) {
swap(this.data, i, parentIndex);
}
}
private void swap(T[] arr, int curIndex, int changeIndex) {
T temp = arr[curIndex];
arr[curIndex] = arr[changeIndex];
arr[changeIndex] = temp;
}
private void swim() {
if (isEmpty()) {
return;
}
int curIndex = 0;
int leftIndex = getLeftChildIndex(curIndex);
int changeIndex = leftIndex;
while (leftIndex < this.size) {
if (leftIndex + 1 < this.size && data[leftIndex].compareTo(data[leftIndex + 1]) < 0) {
changeIndex = leftIndex + 1;
}
if (data[curIndex].compareTo(data[changeIndex]) > 0) {
break;
}
swap(this.data, curIndex, changeIndex);
curIndex = changeIndex;
leftIndex = getLeftChildIndex(curIndex);
changeIndex = leftIndex;
}
}
private void swim2() {
if (isEmpty()) {
return;
}
T rootEle = this.data[0];
int curIndex = 0;
int leftIndex = getLeftChildIndex(curIndex);
int changeIndex = leftIndex;
while (leftIndex < this.size) {
if (leftIndex + 1 < this.size && data[leftIndex].compareTo(data[leftIndex + 1]) < 0) {
changeIndex = leftIndex + 1;
}
if (rootEle.compareTo(data[changeIndex]) > 0) {
break;
}
data[curIndex] = data[changeIndex];
curIndex = changeIndex;
leftIndex = getLeftChildIndex(curIndex);
changeIndex = leftIndex;
}
data[curIndex] = rootEle;
}
public T getPriorityFirst() {
return data[0];
}
public T removeMax() {
if (isEmpty()) {
throw new IllegalArgumentException("heap is null!");
}
T result = this.data[0];
this.data[0] = this.data[size - 1];
this.size--;
swim2();
return result;
}
public void replace(T newEle) {
this.data[0] = newEle;
swim2();
}
public void heapify() {
if (this.data == null || this.data.length == 0) {
return;
}
for (int lastEleParentIndex = (this.data.length - 1 - 1) / 2; lastEleParentIndex >= 0; lastEleParentIndex--) {
heapifySwim(this.data, lastEleParentIndex, this.data.length);
}
}
private void heapifySwim(T[] arr, int lastEleParentIndex, int length) {
int curIndex = lastEleParentIndex;
int leftIndex = getLeftChildIndex(curIndex);
int changeIndex = leftIndex;
while (leftIndex < length) {
if (leftIndex + 1 < length && arr[leftIndex].compareTo(arr[leftIndex + 1]) < 0) {
changeIndex = leftIndex + 1;
}
if (arr[curIndex].compareTo(arr[changeIndex]) > 0) {
break;
}
swap(arr, curIndex, changeIndex);
curIndex = changeIndex;
leftIndex = getLeftChildIndex(curIndex);
changeIndex = leftIndex;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
int i = 0;
while (i < size) {
sb.append(this.data[i]);
if (i != size - 1) {
sb.append(",");
}
i++;
}
sb.append("]");
return sb.toString();
}
}
优先队列
普通队列: 先进先出
优先队列:出队顺序和入队顺序无关,和优先级有关。当访问元素时,优先级最高的会被删除。可以使用堆这种数据结构作为优先队列的底层结构
队列接口:
public class MySelfPriorityQueue<T extends Comparable<T>> implements Queue<T> {
private MaxHeap<T> heap;
public MySelfPriorityQueue() {
heap = new MaxHeap<>();
}
@Override
public int getSize() {
return heap.getSize();
}
@Override
public boolean isEmpty() {
return heap.isEmpty();
}
@Override
public void enqueue(T ele) {
heap.add(ele);
}
@Override
public T dequeue() {
return heap.removePriorityFirst();
}
@Override
public T getFront() {
return heap.getPriorityFirst();
}
}
pty() { return heap.isEmpty(); }
@Override
public void enqueue(T ele) {
heap.add(ele);
}
@Override
public T dequeue() {
return heap.removePriorityFirst();
}
@Override
public T getFront() {
return heap.getPriorityFirst();
}
}
|