数据结构-堆和优先队列

本文详细介绍了堆的概念,包括堆的定义、满二叉树和完全二叉树的特性,以及堆的性质。重点讲解了如何向堆中添加元素(上浮操作)和取出优先级最高的元素(下沉操作)。还分析了堆排序的时间复杂度,指出插入元素的复杂度为O(logn),堆排序的总复杂度为O(nlogn)。同时提供了堆的完整代码实现。
摘要由CSDN通过智能技术生成

1、堆的概念

(1)是一颗完全二叉树
(2)父亲节点的优先级高于或低于左右孩子的优先级(值越大,优先级越高)

2、满二叉树

(1)除叶子节点之外,所有节点都有左右子树
(2)叶子节点都在最后一层
(3)每一层节点的个数:2^(l-1),l为层数
(4)叶子节点的个数:2^(h-1),h代表树高度
(5)非叶子节点的个数:2^(h-1)-1
(6)节点个数:2^(h)-1

3、完全二叉树(数组可以为完全二叉树)

二叉堆是一颗完全二叉树
完全二叉树:按照树的结构,从左到右依次排列
在这里插入图片描述

4、堆的性质 (假设索引从1开始)

(1)根节点没有父节点
(2)除根节点以外的任意节点(i) 的父亲节点的索引为: parent = i/2
(3)任意节点的左孩子节点的索引为:leftIndex = 2i
(4)任意节点的右孩子节点的索引为:rightIndex=(2
i)+1
eg:如果根节点索引为0的位置上:
(1)除根节点以外的任意节点(i) 的父亲节点的索引为: parent = (i-1) /2
(2)任意节点的左孩子节点的索引为:leftIndex =(2i)+1
(3)任意节点的右孩子节点的索引为:rightIndex=(2
i)+2

5、向堆中添加元素(上浮 float up)

1、添加元素52,添加到数组中索引为size的位置,然后更新size
在这里插入图片描述
2、从最后一个节点开始与父亲节点进行(优先级)比较,如果父亲节点的优先级低于当前节点,则进行交换
3、重复步骤二
4、直至根节点或父亲节点的优先级高于当前节点
在这里插入图片描述

    //上浮,父亲节点的优先级大于自身,结束上浮
    //已经上浮到root,结束上浮
    private void floatUp(int i) {
   
        //获取父节点
        int currIndex=i;
        int parentIndex =getparentIndex(currIndex);
        //比较优先级,如果父索引优先级高,不进行交换
        while (currIndex>0&&data[currIndex].compareTo(data[parentIndex])>0){
   
            swap(this.data,currIndex,parentIndex);
            currIndex=parentIndex;
            parentIndex=getparentIndex(currIndex);
        }

    }

在这里插入图片描述

6、取出堆中优先级最高的元素(下沉swim)

最大堆中优先级最高的元素是索引为0的元素
1、使用最后一个元素替换索引为0元素,更新size
2、从索引为0的位置开始进行下沉操作:
(1)找到当前节点左右孩子节点中优先级较高的节点
(2)如果当前节点的优先级小于左右孩子节点中优先级较高的节点,则进行交换
![在这里插入图片描述](https://img-blog.csdnimg.cn/ba2b623e91e04481833901eec1ec4c3a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6auY5py
(3)重复步骤二
(4)直至叶子节点或左右孩子节点中优先级较高的节点小于当前节点的优先级
在这里插入图片描述

 private void swim() {
   
        //判断是否为空
        if (isEmpty()){
   
            return;
        }
        //下沉从根节点开始
        int curIndex =0;
        int leftIndex =getleftIndex(curIndex);
        int changeIndex=leftIndex;
        //有左孩子的条件 leftIndex<this.size
        while (leftIndex<this.size){
   
            if (leftIndex+1<this.size&&data[leftIndex].compareTo(data[leftIndex+1])<0){
   
                changeIndex=leftIndex+1;
            }
            if (data[curIndex].compareTo(data[changeIndex])>0){
   
                break;
            }
            swap(this.data,curIndex,changeIndex);
            curIndex=changeIndex;
            leftIndex=getleftIndex(curIndex);
            changeIndex=leftIndex;
        }
    }

在这里插入图片描述

7、堆的时间复杂度分析

从上面的分析图,可以得出,无论进行上浮还是下沉操作,最多交换的次数为整棵树的高度h
O(h) = O(logn)

8、Heapify和Replace

replace :取出最大元素后,放入一个新元素
实现方式:直接将堆顶元素替换成新元素,然后进行sift down操作


    //replace操作,取出优先级最高的元素,放入一个新元素(让新元素替换索引为0的元素)
    public void replace(T newEle){
   
        this.data[0]=newEle;
        swim();
    }

heapify:将任意数组整理成堆的形状
实现方式:从最后一个元素的父亲节点开始进行调整(sift down) ,直到根节点
1、找到最后一个元素的父亲节点(size-1-1)/2
2、循环进行下沉操作, 直至根节点
在这里插入图片描述

  //heapify:将任意数组整理成堆
    /*
   1、依次添加
   2、从最后元素的父亲节点开始依次进行swim操作,直到root
   */
    public void heapify(){
   
        if (this.data==null&&this.data.length==0){
   
            
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值