数据结构-堆小结

总结堆的几种操作:删除操作(调整堆),添加堆

调整堆:例如在进行删除操作的时候,我们将根结点与最后一个节点进行替换,替换以后,删除掉最后一个节点或在将lastSize(记录数组大小的指针)前移。

int lastSize=0;
void reshape(int[] heap,int root){
    boolean done=false;//判断orphan是否大于largeChild,用来跳出循环
    int orphan=heap[root];//删除操作均是对root的调整
    int leftIndex=root*2;//左孩子的下标
    while (!done&&leftIndex<=lastSize){
        int largeChild = leftIndex;
        int rightIndex = leftIndex+1;
        if (rightIndex<=lastSize&&heap[leftIndex]<heap[rightIndex])largeChild=rightIndex;//判断一下左右孩子中最大的
        if (orphan<heap[largeChild]){
            heap[root]=heap[largeChild];//交换,并依次调整孩子
            root=largeChild;
            leftIndex=root*2;
        }else {
            done=true;
        }
        heap[root]=orphan;
    }
}
void del(int[] heap){
    if(lastSize<1)return;//这里的0下标位置空出来了,最小下标为1
    heap[1]=heap[lastSize];//根节点进行替换
    lastSize--;//删除最后一个元素
    reshape(heap,1);//调整根节点
}

添加元素也是包括两种操作,1是将最新的下标加入到末尾位置2调整,这里的调整是从下向上进行调整。
void add(int[] heap,int val){
    int newIndex=lastSize+1;//插入的位置
    int parentIndex=newIndex/2;//插入节点的父亲下标
    while (parentIndex>0&&val>heap[parentIndex]){//父节点下标大于1,插入节点的值大于父亲节点
        heap[newIndex]=heap[parentIndex];//插入到子节点中
        newIndex=parentIndex;//依次进行相同的操作
        parentIndex=newIndex/2;
    }
    heap[parentIndex]=val;
    lastSize++;
}
时间复杂度分析
首先考虑建堆的过程,有两种方式建堆,1每个元素添加到数组中,添加一次,并进行依次的调整。添加一个元素的平均时间复杂度是O(logn),添加n个元素的平均时间复杂度是O(nlogn)
2将整个数组直接进行建堆的过程,时间复杂度是O(n),下面就分析一下为什么时间复杂度是这样的。
首先针对第一种情况,调整堆的时间复杂度是树的高度h=logn,第一次只有一个元素,log1,第二次有两个元素,log2.依次递推,时间复杂度为log1+log2+log3+...+logn< nlogn。这里考虑时间复杂度的上界。
还有一种比较严格的计算方法,使用斯特林不等式。
图1

针对第二种情况,对整个数组进行建堆。时间复杂度O(n)
图2

这里出现的几个字母,第一个是h,h是树的深度,为logN,l为某一层,树的深度是从1开始到h-1,因为最后一层是不参与调整的。每次调整的时间复杂度就是树的深度,每次调整需要调整的元素就是某一层的节点的个树,这个值为2^(l-1)
因此可以写出如上所示的公式。
 
另外考虑堆排序的时间复杂度,首先刚才已经确定数组建堆的时间复杂度最好为O(n),堆调整的平均复杂度为O(logn),堆排序需要每次将堆首元素删除,一共要出n次,时间复杂度是O(nlogn)。
所以堆排序的时间复杂度为O(nlogn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值