堆的操作(Java)

1.堆的存储方式

由堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来存储堆。
在这里插入图片描述
注意:
对于非完全二叉树,则不适合使用顺序的方式进行存储。因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。
然后针对这种存储方式,要对完全二叉树进行操作的时候,直接取下标即可:
1)如果i为0,则i表示的结点为根节点,否则i的双亲结点为(i-1)/2;
2)如果2i+1小于结点个数个数,则结点的左孩子下标为2i+1,否则没有左孩子;
3)如果2i+2小于结点个数,则结点i的右孩子下标为2i+2,否则没有右孩子。

2.堆的创建

堆的创建:给定一个数组,整理成堆这样的结构(转换完全二叉树并且使用数组来存储,满足下标条件,满足下标关系,还满足堆的条件)

2.1向下调整

向下调整的思路(以大堆为例):
从待调整的位置出发作为父节点,然后根据下标关系得到他的子树,然后找到他的子树的最大值,然后他的孩子结点指向左右子树的最大值,然后拿他的最大值与父节点的值做比较,若不满足堆的大小,则交换两个元素。

public class Heap {
    //向下调整是创建堆的一个核心操作
    //前提条件是当前被调整的左右子树都是堆
    //方法参数中给出堆表示当前元素有效位置的大小
    //可以通过arr.length,这个大小是整个大小
    //index是表示从这个位置开始向下进项调整
    private void shiftDown(int [] arr ,int size,int index){
     //调整过程中,从待调整的位置出发
        //取出该结点的左右子树(通过下标换算的方式)
        //若当前是大堆,找出左右孩子中较大的值
        int parent=index;
        int child=2*parent+1;
        while(child<size){
          //需要找到左右子树中较大的值
            //左右子树下标差1
          if(child+1<size&&arr[child+1]>arr[child])  {
              child=child+1;
          }
          //当左右子树遍历执行完之后,child就指向左右子树中较大的值
            //拿父节点和当前较大的结点去比较,看是否满足大堆的要求
            if(arr[parent]<arr[child]){
                //不满足大堆的要求,交换两个元素
                int tmp=arr[parent];
                arr[parent]=arr[child];
                arr[child]=tmp;
            }else{
                break;
            }
            parent=child;
            child=2*index+1;
        }
    }

    //建堆操作
    public void createHeap(int [] arr){
      //基于向下建堆的操作;
      //从最后一个结点的父节点往前,对于每个下标从后往前向下调整即可
        //或者最后一个非叶子结点
        for(int i=(arr.length-1-1)/2;i>=0;i--){
            shiftDown(arr,arr.length,i);
        }
    }
}

2.2向上调整

向上调整的基本思路(大堆为例):
首先从当前结点出发作为子节点,然后根据下标的关系表达找到他的父节点,如果双亲比孩子大,则满足堆的性质,调整结束,反之,将两个结点进行交换。然后将结点向上移动。

public  static void shiftUp(int [] arr,int size,int index){
        int child=index;
        int parent=(child-1)/2;
        //如果child为0,已经调整到最上面了
        while(child>0){
            if(arr[parent]<arr[child]){
            //不符合大堆要求
                //交换两个元素
                int tmp=arr[parent];
                arr[parent]=arr[child];
                arr[child]=tmp;
        }else{
                break;
            }
            child=parent;
            parent=(child-1)/2;
        }
    }

3.堆的操作

3.1元素插入堆

堆的插入总共需要两个步骤:
1)先将元素放在数组末尾(空间不够时可以扩容)
2)然后将新插入的结点进行向上调整,直到满足堆的条件即可。

public  static void shiftUp(int [] arr,int size,int index){
        int child=index;
        int parent=(child-1)/2;
        //如果child为0,已经调整到最上面了
        while(child>0){
            if(arr[parent]<arr[child]){
            //不符合大堆要求
                //交换两个元素
                int tmp=arr[parent];
                arr[parent]=arr[child];
                arr[child]=tmp;
        }else{
                break;
            }
            child=parent;
            parent=(child-1)/2;
        }
    }

    private int [] arr=new int[100];
    private int size=0;
    //往堆中插入元素
    public void offer(int val){
      if(size>=arr.length) {
          return ;
      }
      arr[size]=val;
      size++;
      //把最后的元素进行向上调整
        shiftDown(arr,size,size-1);
    }

3.2取堆顶元素

堆顶元素是第一个元素,结果是显然的。

public class Heap{
//获取堆顶元素
    public Integer peek(){
        if(size==0){
            return null;
        }
        return arr[0];
    }
  }

3.3删除堆顶元素

基本思路:
采用移形换影,拿0号元素(要删除的元素)和最后一个元素交换,然后size–,然后进行向下调整。

//删除元素(一定是删除堆顶元素)
    public Integer poll(){
        if(size==0){
            return null;
        }
        //拿0号元素(要删除的元素)和最后一个元素交换
        //size--
        //然后向下调整
        int result=arr[0];
        //交换0号元素和size-1项元素
        int tmp=arr[0];
        arr[0]=arr[size-1];
        arr[size-1]=tmp;
        size--;
        shiftDown(arr,size,0);
        return result;
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值