堆的代码实现

因为11.2那篇博客已经讲了基本概念,此处不多赘述。

需要注意的是我们现在讲的建堆与堆排序是有一定区别的。

目录

一、思路阐述(以大根堆为例)

二、具体代码详解

1.定义基本属性

2.向下调整

 3.插入元素

4.向上调整

 5.删除元素

 6.交换

 7.输出堆及读取堆顶元素

 三.完整代码

一、思路阐述(以大根堆为例)

1.建堆的核心:对每一个子树来说根节点始终满足大于等于它的左右子树,从最后一个度不为0的根节点开始,与他的左右子树作比较和交换(后面简称为向下调整)。交换完成后,向前一个根节点移动,重复上述操作。

2.我们还应该加入基本的修改操作,比如插入、删除、读队顶元素、堆内大小、输出堆等等一系列操作。

二、具体代码详解

数组以{27,15,19,18,28,34,65,49,25,37}为例创建大根堆。

1.定义基本属性

数组、容量、大小、父节点如何定义都要有所体现(找到最后一个度不为0的节点以及之前的所有根节点是重点)

 

 //定义属性
    private  int[] elementDate;//数组
    private  int  size;
    private  int DEFAULT_CAPACITY= 10;//默认容量
    public  Heap(){
        this.elementDate =new int[DEFAULT_CAPACITY];
        this.size=0;
    }
    public  Heap(int[] array){
        //重新复制数字 防止外部修改对堆内数据的影响
        this.elementDate = Arrays.copyOf(array,array.length);
        this.size=elementDate.length;
        //寻找最后一个父节点
        int parent=(size-1-1)/2;
        //从最后一个父节点开始向下调整
        for(int i=parent;i>=0;i--){
            shiftDown(i);
        }
    }

2.向下调整

通过父节点找到孩子节点:

第一种情况:只有左孩子,只需让左孩子与父节点作比较,符合条件交换。

第二种情况:既有左孩子又有右孩子,左右孩子先做比较,最大的和父节点作比较,符合条件作交换。

 

private  void shiftDown(int parent){
        if(parent<0){
            return;
        }
        //找到左孩子
        int child=parent*2+1;
        //判断是否有孩子
        while(child<size){
            //有右孩子的情况,左右孩子作比较,child赋给大的值
            if(child+1<size){
                if(elementDate[child]<elementDate[child+1]){
                    child++;
                }
            }
            //最大的值与父节点作比较 父节点大不做操作
            if(elementDate[parent]>=elementDate[child]){
                break;
            }
            //如果父节点小 做交换
            swap(elementDate,parent,child);
            //并继续向下调整
            parent=child;
            child=parent*2+1;
        }

    }

 3.插入元素

插入新元素到最后一个节点时,和最后一个度不为0的根节点(也就是此时它的父节点作比较)作比较,如果没有他的父节点大时,不需要调整。否则,一直向上调整。

 //插入元素
    public  void  offer(int value){
        if(isFull()){
            //二倍扩容把新元素放在最后一个节点后面
            elementDate=Arrays.copyOf(elementDate,elementDate.length*2);
        }
        elementDate[size]=value;
        //长度加一
        size++;
        //调整新节点的位置
        shiftup(elementDate[size-1]);
    }
    private boolean isFull() {
        return size==elementDate.length;
    }

4.向上调整

向上调整只针对插入元素,因为新插入的元素是在最后堆尾,我们需要重新调整它到正确的位置,就需要它向上移动。

private void shiftup(int child) {
        if(child>=size){
            return;
        }
        //找到父节点和父节点比较大小
        int parent=(child-1)/2;
        while(child>0&&parent>=0){
            //没有父节点值大时调整完成
            if(elementDate[child]<=elementDate[parent]){
                break;
            }
            //否则交换该值与父节点
            //并依次向上调整
            swap(elementDate,parent,child);
            child=parent;
            parent=(child-1)/2;
        }
    }

 5.删除元素

删除堆顶元素时,将堆顶元素与堆尾元素做交换,size--就删除了,新的堆顶元素需要向下调整找到适合的位置。

//删除元素
    public int poll(){
        if(isEmpty()){
            throw  new RuntimeException("数组为空");
        }
        //交换堆顶和堆尾两个元素
        int value=elementDate[0];
        swap(elementDate,elementDate[0],elementDate[size-1]);
        //新的堆顶元素向下做调整
        size--;
        shiftDown(0);
        return value;
    }
    private boolean isEmpty() {
        return size==0;
    }

 6.交换

插入、删除、向上调整、向下调整都会用到的交换方法。主要是在调整位置比较大小需要交换位置时使用。

private void swap(int[] elementDate, int parent, int child) {
        int temp=elementDate[parent];
        elementDate[parent]=elementDate[child];
        elementDate[child]=temp;
    }

 7.输出堆及读取堆顶元素

从0下标节点开始依次输出元素,并用“,”隔开

读取堆顶元素(0下标元素)

public  void display(){
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        for(int i=0;i<size;i++){
            sb.append(elementDate[i]);
            if(i<size){
                sb.append(",");
            }
        }
        sb.append("]");
        System.out.println(sb);
    }
    public int peek(){
        return elementDate[0];
    }

 三.完整代码

import java.util.Arrays;
public class Heap {
    //定义属性
    private  int[] elementDate;//数组
    private  int  size;
    private  int DEFAULT_CAPACITY= 10;//默认容量
    public  Heap(){
        this.elementDate =new int[DEFAULT_CAPACITY];
        this.size=0;
    }
    public  Heap(int[] array){
        //重新复制数字 防止外部修改对堆内数据的影响
        this.elementDate = Arrays.copyOf(array,array.length);
        this.size=elementDate.length;
        //寻找最后一个父节点
        int parent=(size-1-1)/2;
        //从最后一个父节点开始向下调整
        for(int i=parent;i>=0;i--){
            shiftDown(i);
        }
    }
    //插入元素
    public  void  offer(int value){
        if(isFull()){
            //二倍扩容把新元素放在最后一个节点后面
            elementDate=Arrays.copyOf(elementDate,elementDate.length*2);
        }
        elementDate[size]=value;
        //长度加一
        size++;
        //调整新节点的位置
        shiftup(elementDate[size-1]);
    }
    private boolean isFull() {
        return size==elementDate.length;
    }
    //向上调整
    private void shiftup(int child) {
        if(child>=size){
            return;
        }
        //找到父节点和父节点比较大小
        int parent=(child-1)/2;
        while(child>0&&parent>=0){
            //没有父节点值大时调整完成
            if(elementDate[child]<=elementDate[parent]){
                break;
            }
            //否则交换该值与父节点
            //并依次向上调整
            swap(elementDate,parent,child);
            child=parent;
            parent=(child-1)/2;
        }
    }
    //删除元素
    public int poll(){
        if(isEmpty()){
            throw  new RuntimeException("数组为空");
        }
        //交换堆顶和堆尾两个元素
        int value=elementDate[0];
        swap(elementDate,elementDate[0],elementDate[size-1]);
        //新的堆顶元素向下做调整
        size--;
        shiftDown(0);
        return value;
    }
    public  void display(){
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        for(int i=0;i<size;i++){
            sb.append(elementDate[i]);
            if(i<size){
                sb.append(",");
            }
        }
        sb.append("]");
        System.out.println(sb);
    }
    public int peek(){
        return elementDate[0];
    }
    private boolean isEmpty() {
        return size==0;
    }

    private  void shiftDown(int parent){
        if(parent<0){
            return;
        }
        //找到左孩子
        int child=parent*2+1;
        //判断是否有孩子
        while(child<size){
            //有右孩子的情况,左右孩子作比较,child赋给大的值
            if(child+1<size){
                if(elementDate[child]<elementDate[child+1]){
                    child++;
                }
            }
            //最大的值与父节点作比较 父节点大不做操作
            if(elementDate[parent]>=elementDate[child]){
                break;
            }
            //如果父节点小 做交换
            swap(elementDate,parent,child);
            //并继续向下调整
            parent=child;
            child=parent*2+1;
        }

    }

    private void swap(int[] elementDate, int parent, int child) {
        int temp=elementDate[parent];
        elementDate[parent]=elementDate[child];
        elementDate[child]=temp;
    }

    public static void main(String[] args){

        int[] array={27,15,19,18,28,34,65,49,25,37};
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LAKURRAA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值