数据结构-堆

来源:互联网 发布:制作条形码的软件 编辑:程序博客网 时间:2024/06/04 19:54

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

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

这里写图片描述

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

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

然后来演示一下如何在堆中插入数据、
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 ;    }}

图片来源于互联网

原创粉丝点击