二叉堆

二叉堆之 Java的实现

二叉堆简介

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

二叉堆一般都通过"数组"来实现,下面是数组实现的最大堆和最小堆的示意图:
在这里插入图片描述

基本操作

二叉堆通常使用数组来实现(实际上可以用ArrayList,因为底层就是数组),数组实现的二叉堆,从根节点往下一层一层在数组依次摆放,父节点和子节点的位置存在一定的关系

假设"第一个元素"在数组中的索引为 0 的话,则父节点和子节点的位置关系如下:

① 索引为i的左孩子的索引是 (2*i+1);

② 索引为i的右孩子的索引是 (2*i+2);

③ 索引为i的父结点的索引是 floor((i-1)/2);

1. 插入

当向最大堆中添加数据时:先将数据加入到最大堆的最后,然后尽可能把这个元素往上挪,直到挪不动为止!
例子:在最大堆[90,80,70,60,40,30,20,10,50]中添加85
在这里插入图片描述
代码实现:

	private int[] values = new int[16] ;

    private int size;
    /**
     * 上浮
     * @return
     */
    private int fixUp() {
        int  j = size -1 ;   //最后一个元素的下标
        int f ; //父节点的下标
        while((f = ((j -1) /2)) >= 0) { //通过父节点的下标
            if(values[f] <= values[j]) 
            	break; //父节点的值小于子节点的值,则打适合的位置。
            int temp = values[f] ; 
            values[f] = values[j]; 
            values[j] = temp ;
            j = f ;
        }
        return f;
    }

    /**
     * 添加一个元素在最小堆中上
     * @return
     */
    public int push(int item) {
        if(size >= values.length) Arrays.copyOf(values, size << 1) ;
        values[size++] = item ;
        return fixUp();
    }

2. 删除

先删除该数据,然后用最大堆中最后一个的元素插入这个空位;接着,把这个“空位”尽量往上挪,直到剩余的数据变成一个最大堆
例子:从最大堆[90,85,70,60,80,30,20,10,50,40]中删除90
在这里插入图片描述
例子:从最大堆[90,85,70,60,80,30,20,10,50,40]中删除60
在这里插入图片描述
代码实现

  /**
     * 移除并获取一个堆顶元素
     * @return 堆顶元素
     */
    public int poll() {
        if(size <= 0) throw new IllegalStateException("不存在元素");
        int value = values[0];
        values[0] = values[--size] ; //将最后一个元素提到堆顶
        values[size] = 0 ; //清空最后一个的数据
        fixDown(); //下沉操作
        return value;
    }


    /**
     * 下沉
     * @return 下沉到适合位置的index
     */
    private int fixDown() {
        int f = 0 ; //父节点的index
        int k ;  //较小者子节点的index
        while((k = (f << 1) + 1) < size) { //至少存在左子节点
            if(k < size - 1) {   //存在右子节点
                if (values[k] > values[k + 1]) k++; //左右子节点进行比较。
            }
            if(values[f] <= values[k]) break; //父节点小于较小者子节点,则找到合适的位置,退出循环
            int temp = values[f] ; values[f] = values[k]; values[k] = temp ;
            f = k ;
        }
        return f;
    }

3. 完整代码

/**
 * 最小堆的超简化版实现  
 * Created by wang007 on 2018/6/12.
 */
public class MinHeap {

    private int[] values = new int[16] ;

    private int size;


    /**
     * 移除并获取一个堆顶元素
     * @return 堆顶元素
     */
    public int poll() {
        if(size <= 0) throw new IllegalStateException("不存在元素");
        int value = values[0];
        values[0] = values[--size] ; //将最后一个元素提到堆顶
        values[size] = 0 ; //清空最后一个的数据
        fixDown(); //下沉操作
        return value;
    }


    /**
     * 下沉
     * @return 下沉到适合位置的index
     */
    private int fixDown() {
        int f = 0 ; //父节点的index
        int k ;  //较小者子节点的index
        while((k = (f << 1) + 1) < size) { //至少存在左子节点
            if(k < size - 1) {   //存在右子节点
                if (values[k] > values[k + 1]) k++; //左右子节点进行比较。
            }
            if(values[f] <= values[k]) break; //父节点小于较小者子节点,则找到合适的位置,退出循环
            int temp = values[f] ; values[f] = values[k]; values[k] = temp ;
            f = k ;
        }
        return f;
    }

    /**
     * 上浮
     * @return
     */
    private int fixUp() {
        int  j = size -1 ;   //最后一个元素的下标
        int f ; //父节点的下标
        while((f = ((j -1) >>1)) >= 0) { //通过父节点的下标
            if(values[f] <= values[j]) break; //父节点的值小于子节点的值,则打适合的位置。
            int temp = values[f] ; values[f] = values[j]; values[j] = temp ;
            j = f ;
        }
        return f;
    }

    /**
     * 添加一个元素在最小堆中上
     * @return
     */
    public int push(int item) {
        if(size >= values.length) Arrays.copyOf(values, size << 1) ;
        values[size++] = item ;
        return fixUp();
    }

    public static void main(String[] args) {
        MinHeap heap = new MinHeap();
        heap.push(4);
        heap.push(2);
        heap.push(7);
        heap.push(9);
        heap.push(1);
        heap.push(5);
        heap.push(10);
        heap.push(3);
        heap.push(2);
        for (int i = 0 ;i< 9; i++) {
            System.out.println(heap.poll());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值