一. 堆结构
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); } }