一. 堆结构
1.优先队列
- 普通队列:先进先出,后进后出。
- 优先队列:优先级高的先出来,与时间无关、
应用:优先队列在OS的使用,CPU调度时间片,每次优先选择优先级最高的任务执行,注意是动态的~;不仅仅适用于OS,还有在请求某个网页,服务器按需要返回,回应的一般是按照优先队列决定的~
处理问题:之前的排序算法,N个元素选前M个元素,时间复杂度O(nlogn),使用优先队列时,可将时间复杂度降低为O(NlogM)
主要操作:入队,出队(取优先级最高的元素)
可以采取的数据结构:数组(普通,顺序),堆(平均而言要好)
2. 二叉堆(Binary Heap)的基本实现
堆的实现通过构造二叉堆,具有以下性质:
任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
public class MaxHeap<Item> {
private Item[] data;
private int count;
// 构造函数, 构造一个空堆, 可容纳capacity个元素
public MaxHeap(int capacity){
data = (Item[])new Object[capacity+1];
count = 0;
}
// 返回堆中的元素个数
public int size(){
return count;
}
// 返回一个布尔值, 表示堆中是否为空
public boolean isEmpty(){
return count == 0;
}
}
接下来就是往里面添加插入,拿出元素,即shift up, shift down操作
//在最大堆中插入一个新的元素 item
public void insert(Item item){
assert count + 1 <= capacity;
data[count + 1] = item;
count ++;
shiftUp(count);
}
private void shiftUp(int k){
while(k > 1 && data[k/2].compareTo(data[k]) < 0){
swap(k, k/2);
k /= 2;
}
}
private void swap(int i, int j){
Item t = data[i];
data[i] = data[j];
data[j] = t;
}
//从最大堆中取出堆顶元素,即堆中所存储的最大数据
public Item extractMax(){
assert count > 0;
Item res = data[1];
swap(1, count);
count --;
shiftDown(1);
return res;
}
private void shiftDown(int k){
while( 2*k <= count){
int j = 2*k;
if(j+1 <= count && data[j+1].compareTo(data[j]) > 0) j++;
if(data[k].compareTo(data[j]) >= 0) break;
swap(k, j);
k = j; // k就下来了,j是k的子节点
}
}
3. 堆排序:
堆排序:将一个数组中的值一个一个的插入堆中,然后再一个一个的取出来(取出来也只能是最大值)
Heapify:之前的是一个一个的插入,选择将整个数组传入堆的构造方法,这样只需要从最后一个有孩子的结点开始算起~
//构造函数,通过给定一个数组创建一个最大堆,构建堆的过程,时间复杂度为O(n)
public MaxHeap(Item[] arr){
int n = arr.length;
data = (Item[])new Comparable[n+1];
capacity = n;
for(int i = 0; i < n; i ++){
data[i+1] = arr[i];
}
count = n;
for(int i = count/2; i >= 1; i --){
shiftDown(i);
}
}