堆和优先级队列 下沉 上浮 最大堆

堆和优先级队列(内部就是堆)

堆(二叉堆 基于二叉书的堆)

二叉堆:一颗完全二叉树 结构上:完全二叉树

堆中根节点》=子树中的节点值(最大堆、大根堆)小根堆相反;且在堆中只能保证当前节点和和子节点以及父节点之间的大小关系 和层次无关

完全二叉树建议使用顺序表(数组)存储:没有空间的浪费 使用顺序表存储时 如果根节点从0开始排序那么它的子节点就是2k+1 和2k+2一般只需要判断左树就行当2k+1<arr.length;

当判断一个节点的父节点是否存在?只需判断它是否为根节点 换个说法就是判断父节点编号是否>=0即可 父节点的索引为(k-1)>>1  或者只需要看k是否大于0

当我想给最大堆中添加一个新元素 我可以直接在数组的末尾新增元素,再调整结构(siftup)保证为最大堆,

元素上浮的终止条件

1已经走到根节点

2已经走到比父节点小的位置

siftUp(int k);//向上调整为索引为k的节点,使其仍然满足堆的性质

 

package heap;

import java.util.ArrayList;
import java.util.List;

/**
 * @author hututu
 * @date 2022/03/29 18:00
 **/
public class MaxHeap {
    //使用JDK的动态数组arraylist来储存一个最大堆
    //list数组的add方法默认是尾插
    List<Integer> data;
    public MaxHeap(){
        this(10);
    }

    public MaxHeap(int size){
        data=new ArrayList<>(size);//数组初始化
    }
    public  void add(int i){
        data.add(i);
        siftUp(data.size()-1);

    }
 
    public boolean isEmpty(){
        return data.size()==0;
    }

    public  void siftUp(int k){
        //1已经走到根节点k<0或者
        //2已经走到比父节点小的位置
        while (k>0&&data.get(k)>data.get(parent(k))){
            swap(k,parent(k));
            k=parent(k);
        }
    }

    private void swap(int i, int j) {
        int temp=data.get(i);
        data.set(i,data.get(j));
        data.set(j,temp);
    }


    //根据索引得到父节点的索引
    private  int parent(int k){
        return (k-1)>>1;
    }
    private int leftChild(int k){
        return (k<<1)+1;
    }
    private int rightChild(int k){
        return (k<<1)+2;
    }

    @Override
    public String toString() {
        return "MaxHeap{" +
                "data=" + data.toString() +
                '}';
    }
}

 

 对于堆而言堆顶元素就是最值,最大堆的堆顶就是最大值,要想删除一个堆顶元素分为两步,我们取出堆顶元素后,直接将数组末尾的元素顶到堆顶,然后进行下沉(siftDown)操作

这种操作方法还有一个小特别之处就是将原数组遍历完后可以得到一个非递减的数组

 下沉就是把索引为k的节点不断下沉,直到到达最终位置

下沉最终位置条件:2k+1(左子树)>size 或者 当前值>左右子树

 代码如下:

    public int extractMax(){
        if (isEmpty()){
            throw new NoSuchElementException("heap is empty! cannot extract");
        }
        int max=data.get(0);
        //1将数组末尾元素顶到堆顶
        int lastVa=data.get(data.size()-1);
        data.set(0,lastVa);
        //2数组末尾元素删除
        data.remove(data.size()-1);
        //3进行元素的下沉操作
        siftDown(0);
        return max;
    }

    private void siftDown(int k) {
        //当存在子树时
        while (leftChild(k)<data.size()){
            int j=leftChild(k);
            //判断一下是否有子树
            if (j+1<data.size()&&data.get(j+1)>data.get(j)){
                //此时存在右子树且大于左树的值
                j+=1;
            }
            //J为左右子树的最大值 在和当前节点K去比较
            if (data.get(k)>=data.get(j)){
                break;
            }else {
                swap(k,j);
                k=j;
            }
        }

    }

时间复杂度为nlogn 外层为n  hp.add()为一个二叉书的高度logn

       int[] data={65,30,52,11,24,30,25,32,23};
        MaxHeap hp=new MaxHeap();
        for (int i:data) {
            hp.add(i);

        }

        System.out.println(hp);

heapify--堆化操作 可以将任意数组调整为堆的结构 我们可以将任意一个数组看成一个完全二叉树 从当前完全二叉树的最后一个非叶子结点进行元素的下沉操作,即可调整

为堆,时间复杂度为O(n)具体原因如下

heapify的思想就是:从小问题逐步向上走,不断去调整子树,将子树不断变为大树的过程

 

 

int lastNotLeafNode=parent(data.size()-1)

 

  public MaxHeap(int[] arr){
        data =new ArrayList<>(arr.length);
        //1先将arr的所有元素复制到data数组中
        for (int i:arr){
            data.add(i);
        }
        //2从最后一个非叶子节点开始进行siftDown
        for (int i=parent(data.size()-1);i>=0;i--){
            siftDown(i);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是香橙啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值