赞
踩
堆是一种特殊的二叉树。
最小值堆:最小值堆的特性。
对于堆的任意非叶节点K,K的值总是小于或者等于左右子节点。
K <= 左节点;K <= 又节点;
堆实例:
堆实际上是一个完全二叉树(若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。)可以用数组表示。
堆中存储是局部有序的。
创建堆:
交换创建堆,交换有2,1)向下交换,2)向上交换。
1)向下交换。
假设根的左右子树都已是堆,并且根元素为R,此时有2种情况。
(1)R的值小于或者等于左右子结点,此时堆完成。
(2)R的值大于其中一个或者两个子女,此时R应该与两个子女中较小的一个交换,结果得到一个新堆,
R到达新位置后继续和其两个子女,如果R小于或者等于其左右子女,建堆完成,否则重复上一过程,直到
R小于或等于其左右子女,或R成为新的叶结点。
堆的数组实现:
- public abstract class AbstractHeap<T extends Comparable<T>> implements Heap<T> {
-
- //最大堆大小
- private static final int MAX_SIZE = Integer.MAX_VALUE;
-
- //数组大小
- protected int size;
- //堆中数组个数
- protected int currentSize;
- //存储堆的数据
- protected T[] data;
-
- AbstractHeap(){
- this(0,16,null);
- }
-
- AbstractHeap(T[] data){
- this(data.length,data.length,data);
- }
-
- AbstractHeap(int currentSize,int size,T[] data){
- this.currentSize = currentSize;
- this.size = size;
- this.data = data;
- if (data != null)
- //根据给定数组 创建堆
- buildHeap(data);
- }
- }
用给定的数组创建堆,从堆中第一个分支结点,从下往上网上交换创建堆:
- private void buildHeap(T[] t){
- if (t.length > 1){
- //从下到上第一个分支结点
- int pos = t.length / 2 - 1;
- for (int i = pos ; i >= 0 ; i -- ){
- //向下交换
- siftDown(i);
- }
- }
- }
交换函数:
- void siftDown(int pos) {
- // pos为第一个分支结点位置
- int tmp = pos;
- // j为其左结点
- int j = tmp * 2 + 1;
- //保存当前结点值
- T tmpNode = data[tmp];
- while ( j < currentSize){
- //j < currentSize - 1 防止右结点不存在,j+1 = tmp *2 +1 ,data[j+1] 为右结点
-
- if (j < currentSize - 1 && data[j].compareTo(data[j+1]) == 1){
- //若右结点值比较小,j++
- j++;
- }
- if (tmpNode.compareTo(data[j]) == 1){
- //若当前结点值大于左右结点中最小的值,将最小的哪个结点值上移当前结点,
- data[tmp] = data[j];
- //tmp 为上移结点下标
- tmp = j;
- j = j * 2 + 1;
- }
- //如果当前结点值小于其左右子女中最小的,建堆完成,跳出循环
- else break;
- //将当前结点值 赋值给上移结点
- data[tmp] = tmpNode;
- }
- }
2)向上交换
在堆中新增值时,采用向上交换:
- public boolean insert(T t) {
- if (t == null){
- return false;
- }
- if (currentSize == size){
- return false;
- }
- //直接将新增值放到数组的最后一个位置,并向上交换
- data[currentSize] = t;
- siftUp(currentSize);
- currentSize ++;
- return true;
- }
- void siftUp(int pos) {
- //当前位置下标
- int tmp = pos;
- //父结点下标
- int j = (pos - 1) / 2;
- //当前结点
- T tmpNode = data[tmp];
- while (j >= 0){
- //如果当前结点值小于父结点,当前结点值向上移动,直到根结点或者当前结点值打于根结点值跳出循环
- if (tmpNode.compareTo(data[j]) == -1){
- data[tmp] = data[j];
- tmp = j;
- j = j / 2 - 1;
- }else break;
- tmpNode = data[tmp];
- }
- }
创建堆可以根据已有数据创建采用向下移动创建,也可以一个一个的插入值,采用向上移动的方法创建堆。
小结:
堆的特性,父结点的值小于左右子女结点值。
堆保持局部有序性,可以用左优先队列。
堆排序时间复杂度为O(n)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。