数据结构-堆

注意:此案例演示的是最大堆

先来看一下书上对堆的介绍,嫌烦的可以直接往下翻==

这里写图片描述

堆是一个完全二叉树,这里演示的是最大堆,最大堆特点是父节点要大于任何一个子节点
这里写图片描述

堆只是概念上的表示,实际数据还是存在数组里
这里写图片描述

然后来演示一下如何在堆中插入数据、
1:要在如下的堆中插入数据99
这里写图片描述

2:插入时并不是直接插在根节点上,(虽然99在当前堆中是最大的 ),而是插在最后(在数组中表示的话也是最后),(注意:堆是完全二叉树),没明白的百度一下完全二叉树,你就知道为什么要这样插了
这里写图片描述

3:插好之后,可不能往后一插就了事;
按照最大堆的规则:父节点要比任一子节点大,还要向上作比较以确定合适的位置
那么看图:因为99比80大,所以两两互换,99在上,80在下
这里写图片描述

4:然后在进行比较,99比83大,两两互换,99在上,83在下
这里写图片描述

5:然后发现99还是比92大,所以再换,99成根节点了,92下去了
(注意:因为这里插入的数是最大的所以一直交换到根,如果插入不是最大数,在比较过程中发现父节点比插入数大,那么插入数就待原地不动,插入方法结束)
这里写图片描述
这里写图片描述

插入讲完了

下面来讲一下删除

在最大堆中,删除始终删除最大值,也就是其根节点,看下图,最大值为97,我们要删除他
这里写图片描述

删除后,根节点总不能空吧,空了那还是树?所以我们要找一个节点提上去,因为他是完全二叉树,我们不能随便对里面节点操作,所以我们将最后一节点 33 先提上来 ,提上来依旧符合完全二叉树的性质
这里写图片描述
这里写图片描述

33提上来了,这时发现33并不是最大的,放在根节点又不太合适啊,所以还要在做调整,将最大的放到根上来,
33此时为根,从其左右子节点找最大的提上来,然后95上来了,33跑到95原来的地方
这里写图片描述

然后33还是比子节点小,然后在从其左右子节点中找最大的换上来,57最大,所以33和57兑换这里写图片描述
然后33还是小,再换
这里写图片描述
最后,33比0大,所以不换了这里写图片描述

package heap;

public class Node
{
    public int data ;

    public Node ( int data )
    {
        this.data = data ;
    }
}
package heap;

/*
 * 堆在概念上是用完全二叉树,实际上是用数组保存数据
 * 
 * PS:把上面几个操作的流程图看明白再来看代码,理解的更快
 */
public class MaxHeap
{
    private Node [] heapArray ; //堆的实体是一个数组
    private int currentSize ;//数组当前大小
    private int maxSize ;//数组初始化最大长度

    //初始化
    public MaxHeap ( int maxSize )
    {
        this.maxSize = maxSize ;
        currentSize = -1 ;
        heapArray = new Node [maxSize] ;
    }

    //判断是否为空
    public boolean isEmpty () 
    {
        return currentSize == - 1 ;
    }

    //判断是否满
    public boolean isFully ()
    {
        return currentSize == maxSize - 1 ;
    }

    //添加数据
    public boolean insert ( int data )
    {
        //先判断满没满
        if ( isFully () )
        {
            System.out.println ( "Heap is full !" );
            return false ;
        }

        //没满,添加数据 
        Node newNode = new Node ( data ) ;
        //添加新数据,在数组中表示新数据一定是在数组末端
        //在树中,是最下层最后一个节点(叶节点)
        heapArray [ ++currentSize ] = newNode ;

        //但又不能添加后就了事啊,万一新数据比父节点大呢,所以还要在向上调整
        trickleUP ( currentSize ) ;

        return true ;
    }

    //向上调整
    public void trickleUP ( int index )
    {
        //由于堆的具体实现是用数组来实现的,想要确定当前节点的父节点,要比在树中要难
        //那么问题来了,如何在数组中确定当前新数据所对应节点的父节点下标?=_=
        // 有一个公式:(当前节点的数组索引下标 - 1 )/ 2
        int parent = ( index - 1 ) / 2 ;//当前节点的父节点数组索引下标 
        Node current = heapArray [ index ] ;//存放要调整的节点

        //父节点比当前节点小
        while ( index > 0 && heapArray [parent].data < current.data )
        {
            //将父节点移动当前节点的位置
            heapArray [index] = heapArray [parent] ;
            index = parent ;//当前节点下标变成原父节点下标
            parent = (parent-1) / 2 ;//继续比较
        }
        //跳出循环说明要么当前节点到根哪儿了,要么其父节点比他大
        heapArray [index] = current ;
    }

    //删除
    public Node remove ()
    {
        //删除始终删除其根节点,也就是数组下标为0的
        Node root = heapArray [0] ;
        //删除完了,将最后节点提上来
        heapArray [0] = heapArray [currentSize] ;
        currentSize -- ;//原根节点被删了,最后节点又提上去了,所以数组当前长度-1

        //然后向下调整
        trickleDOWN ( 0 ) ;

        return root ;
    }

    //向下调整
    public void trickleDOWN ( int index ) 
    {
        //寻找其此时所对应树结构的左右孩子
        //如何确定左右孩子在数组中的下标
        // left : (index+1)*2-1
        //right: (index+1)*2

        int left = ( index + 1 ) * 2 - 1 ;
        int right = ( index + 1 ) * 2 ;

        if ( left > currentSize )
        {
            return ;
        }

        Node current = heapArray [index] ;

        //如果左子节点比右子节点大
        if ( heapArray [left].data > heapArray [right].data )
        {
            //如果左子节点比当前节点大
            if ( heapArray [index].data < heapArray [left].data )
            {
                heapArray [index] = heapArray [left] ;
                index = left ;
                trickleDOWN ( index ) ;
            }
            //如果左子节点比当前节点小
            else
            {
                return ;
            }
        }
        else//如果左子节点比右子节点小
        {

            如果右子节点比当前节点大
            if ( heapArray [index].data < heapArray [right].data )
            {
                heapArray [index] = heapArray [right] ;
                index = right ;
                trickleDOWN ( index ) ;
            }
            else//如果右子节点比当前节点小
            {
                return ;
            }
        }

        heapArray [index] = current ;
        return ;
    }
}

图片来源于互联网

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值