1、堆是一种特殊的二叉树
堆总是一颗完全二叉树(即除最底层外,其它层节点都被元素填满,且最底层从左向右尽可能填满结点)
2、分为最大堆和最小堆,最大堆中某结点的值总是不大于其父节点的值,最小堆中某结点的值总是不小于其父节点的值
3、堆的实现: 用数组实现 构造二叉树
ArrayList<Integer> array=new ArrayList<Integer>(); //ArrayList<Integer> array=new ArrayList<Integer>(capacity);数组是按层次存放堆这棵二叉树中的结点值的
数组中的元素并不是按从大到小的顺序排列的,从堆中取出元素只能取出堆顶元素,即只能获得最大值或最小值
4、index为数组中当前元素的索引,则该元素的父节点在数组中的索引为(index-1)/2,该元素的左孩子在数组中的索引为2*index+1,该元素的右孩子在数组中的索引为2*index+2
5、以最大堆为例
(1)向堆中添加元素:
时间复杂度:O(logn)
将该元素先添加到数组的尾部(即充当最底层的最后一个叶结点),然后将该元素与其父节点进行大小比较,若大于其父节点则与父节点进行交换,继续与上一层父节点进行比较,如此重复,直至小于等于父节点为止
//向堆中添加元素 public void addValue(ArrayList<Integer> array,int value) { if(array==null) return; array.add(value); int i=array.size()-1; while(i>=1&&value>array.get((i-1)/2)) { array.set(i,array.get((i-1)/2)); array.set((i-1)/2,value); i=(i-1)/2; } }(2)删除堆顶元素:
时间复杂度:O(logn)
将堆顶元素A与最后一个元素B交换后(即数组的首尾元素互换),删除A,从堆顶元素开始比较其与左右孩子的大小,若同时小于左右孩子,则与左右孩子中的较大者交换,否则与大于其的孩子交换,继续与下一层左右孩子进行比较,如此重复,直至大于等于左右孩子为止
removeValue=swap+sift
//删除堆顶元素 public void removeValue(ArrayList<Integer> array) { if(array==null||array.size()==0) return; array.set(0,array.get(array.size()-1)); array.remove(array.size()-1); int i=0; while(2*i+1<array.size()) { int value=array.get(i); int a=array.get(2*i+1); int max=a; int index=2*i+1; //左右孩子都存在 if(2*i+2<array.size()) { int b=array.get(2*i+2); if(b>a) { max=b; index=2*i+2; } } if(value<max) { array.set(i,max); array.set(index,value); i=index; } else break; } }(3)返回堆中的元素个数
return array.size();(4)判断堆是否为空
return array.isEmpty();(5)返回数组索引
//返回父节点在数组中的索引 return (index-1)/2; //返回左孩子在数组中的索引 return 2*index+1; //返回右孩子在数组中的索引 return 2*index+2;(6)替换:将堆顶元素替换为其他元素
时间复杂度:O(logn)
removeValue()+addValue()(7)Heapify:将任意数组转化为堆的形状
时间复杂度:O(n)
将数组看成一棵完全二叉树,从最后一个叶节点的父节点开始,到根节点结束,依次判断各节点与其左右孩子的大小关系并进行调整
0~array.size()-1/2进行sift
public void heapify(ArrayList<Integer> array) { int y=array.size()-1; int i=(y-1)/2; for(int j=i;j>=0;j--) sift(array,j); return; } public void sift(ArrayList<Integer> array,int i) { while(2*i+1<array.size()) { int value=array.get(i); int a=array.get(2*i+1); int max=a; int index=2*i+1; //左右孩子都存在 if(2*i+2<array.size()) { int b=array.get(2*i+2); if(b>a) { max=b; index=2*i+2; } } if(value<max) { array.set(i,max); array.set(index,value); i=index; } else break; } }将n个元素插入一个空堆中,时间复杂度为O(nlogn)
6、优先队列具有最高优先级先出的特点,所以采用最大堆数据结构
java.util.PriorityQueue类底层就是通过优先级堆实现的