最大二叉堆的Java实现

二叉堆的介绍

二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆最小堆
最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

二叉堆一般都通过"数组"来实现,下面是数组实现的最大堆和最小堆的示意图:

 

二叉堆的图文解析

图文解析是以"最大堆"来进行介绍的。
最大堆的核心内容是"添加"和"删除",理解这两个算法,二叉堆也就基本掌握了。下面对它们进行介绍,其它内容请参考后面的完整源码。

1. 添加

假设在最大堆[90,80,70,60,40,30,20,10,50]种添加85,需要执行的步骤如下:

如上图所示,当向最大堆中添加数据时:先将数据加入到最大堆的最后,然后尽可能把这个元素往上挪,直到挪不动为止!
将85添加到[90,80,70,60,40,30,20,10,50]中后,最大堆变成了[90,85,70,60,80,30,20,10,50,40]。


2. 删除

假设从最大堆[90,85,70,60,80,30,20,10,50,40]中删除90,需要执行的步骤如下:

如上图所示,当从最大堆中删除数据时:先删除该数据,然后用最大堆中最后一个的元素插入这个空位;接着,把这个“空位”尽量往上挪,直到剩余的数据变成一个最大堆。
从[90,85,70,60,80,30,20,10,50,40]删除90之后,最大堆变成了[85,80,70,60,40,30,20,10,50]。


注意:考虑从最大堆[90,85,70,60,80,30,20,10,50,40]中删除60,执行的步骤不能单纯的用它的字节点来替换;而必须考虑到"替换后的树仍然要是最大堆"!


最大堆的Java实现:

package com.oracle.SixthCharpter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 实现:将一个数组转化成一个”二叉堆“
 * 二叉堆可以看做成一个近似完全二叉树,除了最后一层节点,其余的是完全二叉树。
 *     二叉堆可以分为“最大堆”和“最小堆”
 *         最大堆:父结点的键值总是大于或等于任何一个子节点的键值;
 *         最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
 * @author zhegao
 *
 */
/**
 * “最大堆”算法——————将一个数组转化成最大二叉堆
 */
public class MaxHeap {
    public int[] myHeap ;
    public int elements;
    public MaxHeap() {
        elements=0;
        myHeap = new int[100];
        
    }
    public MaxHeap(int size) {
        elements=0;
        myHeap = new int[size];
    }
    //向上调整方法,用于实现“插入”
    public void filtUp(int start) {
        int current = start;
        int parent = (current-1)/2;
        int tmp = myHeap[current];
        while(current>0) {
            if(myHeap[parent]>=tmp) {
                break;
            }else {                
                myHeap[current]=myHeap[parent];
                current = parent;
                parent = (current-1)/2;
            }
        }
        myHeap[current]=tmp;
    }

    //插入方法
    public void insertNode(int arr) {
        myHeap[elements++]=arr;
        filtUp(elements-1);
    }

    //向下调整方法,用于实现“删除”
    //通过父节点找到其下面的两个子节点,并比较,选择其中较大的那个作为替换的对象
    public void filtDown(int start) {
        int current = start;
        int leftChild = current*2+1;    
        int tmp = myHeap[current];

    //“向上翻越”的复杂度为O(lgn)

        while(current<=(elements-3)/2) {
            leftChild = myHeap[leftChild]>myHeap[leftChild+1]?leftChild:leftChild+1;
            if(myHeap[leftChild]<tmp) {
                break;
            }else {
                myHeap[current] = myHeap[leftChild];
                current = leftChild;
                leftChild = current*2+1;                
            }
        }
        myHeap[current]=tmp;
    }
    //删除方法
    public void remove(int index) {
        //拿到最后一个节点
        int node = myHeap[elements-1];
        myHeap[index]=node;
        elements--;
        filtDown(index);
        
    }
    
    //实现一个数组转化成一个“最大二叉堆”
    public int[]  getMaxHeap(int[] arr) {
        for(int i=0;i<arr.length;i++) {
            insertNode(arr[i]);
        }
        return myHeap;
    }
    public void display() {
        for(int i=0;i<elements;i++) {
            System.out.print(myHeap[i]+" ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        int[] arr = new int[] {0,1,2,3,4};
        MaxHeap prac = new MaxHeap();
        
        //将数组转化成最大二叉堆
        prac.getMaxHeap(arr);
        prac.display();
      
        prac.remove(0);

        prac.display();

 }

}