堆
- 定义:二叉堆,每个节点的值大于等于他的两个子节点;
- 采用的数据结构:数组,二叉堆层次遍历存放在数组中,通过下标找到孩子、父亲结点,2k、2k+1、k/2,保证对数级别的时间复杂度实现插入(新插入的元素放在数组尾部,逐渐上升,调整维护堆的性质)和删除最大元素(删除堆顶,调整);
- 关键操作:
- Be:数组中从1开始存储元素;
- 由下至上的堆的有序化:节点比其父节点的值大,需要交换
public void exchange(int[] nums,int i,int j){ int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } public void swim(int[] nums,int k){ while(k>1 && nums[k]>nums[k/2]){ exchange(nums,k,k/2); k = k/2; } }
- 由上至下的堆有序化:父节点比孩子节点值小、
public void sink(int[] nums,int k,int N){//N元素的个数 while(2*k <= N){ int j = 2*k; if(j<N && nums[j]<nums[j-1]) j++;//j不是最后一个节点,而且他比右节点小,所以这一步找到了最大的孩子 if(nums[k] >= nums[j]) break;//顺序正确,不需调整 exchange(nums,k,j); k = j; } }
- 插入:将元素增加至末尾,增大N,swim调整顺序;
- 删除最大值:保存最大值nums[1],将nums[N]移动至堆顶,减小N值,重新调整;
public void insert(int[] nums,int N,int ele){ nums[++N] = ele; swim(nums,N); } public int delete(int[] nums,int N){ int max = nums[N]; exchange(nums,1,N); N--; nums[N] = 0;//置空 sink(nums,1,N); return max; }
- 堆的构造与排序
- N个元素构造堆,一个一个插入已排序的堆中,用swim,复杂度NlogN;
public void heap_sort(int[] nums,int N){ /*使用sink构造堆,从中间开始,N/2--N之间的都是叶子节点 *如果一个节点的两个子节点都已经是堆了,那么在该节点上调用sink就可以将他们变成一个堆*/ for(int k=N/2;k>=1;k--) sink(nums,k,N); /*构造最大堆,将堆顶元素和N交换,N就是最大值了,之后sink维护堆的性质*/ while(N > 1){ exchange(nums,1,N--); sink(nums,1,N); } }