《堆排序|维护堆和建堆》

堆可以看作各个元素之间有前后续的特殊数组,当然也是一颗完全二叉树。设堆heap的元素为heap[1,2,3,...,heap_size]。注意0<=heap_size<=heap.len,并且节点从1开始计数(便于计算)。

1. 寻找节点

1.1 寻找父节点

若节点编号为 i i i,那么他的父节点为 i 2 \frac{i}{2} 2i向下取整。代码实现如下:

/**
 * 求节点i的父节点
 */
int parent(int i){
    return i/2;
}

1.2 寻找左孩子

若节点编号为 i i i,那么他的左孩子节点为 2 i 2i 2i。代码实现如下:

/**
 * 求左孩子
 */
int left(int i){
    return 2*i;
}

1.3 寻找右孩子

若节点编号为 i i i,那么他的左孩子节点为 2 i 2i 2i+1。代码实现如下:

/**求右孩子 
 * 
*/
int right(int i){
    return 2*i+1;
}

2. 维护堆

  • 在堆nums中维护第i个节点为根的树

参数说明:

  • nums:表示待维护的堆
  • i表示待维护的节点
  • 返回值若为1则说明该堆被维护过,返回值为0则说明该堆不需要被维护
  • 注:堆的第一个元素nums[0]存储堆内有效数据的长度,建堆的时候应该明确给出
  • 使用flag来监视程序是否更改堆的顺序
int maxHeapIfy(int nums[], int i){
    int l = left(i);
    int r = right(i);
    int largest;
    int heapSize = nums[0];

    //flag用于判断是否被维护过
    int flag = 0;

    //判断左子树和根节点哪个大,选出大的节点设为largest
    if(l <= nums[0] && nums[l]>nums[i]){
        largest = l;
    }else{
        largest = i;
    }

    //比较largest和右节点那个大,选出大节点作为largest
    if( r <= nums[0] && nums[r]>nums[largest]){
        largest = r;
    }

    //若largest != i则说明该节点为根的树需要调整
    if(largest != i){
        flag=1;
        int exchange;
        exchange = nums[largest];
        nums[largest] = nums[i];
        nums[i] =  exchange;

        maxHeapIfy(nums , largest);
    }
    
    return flag;
}

3. 建堆

直接按照输入数组,从最后一个非叶子节点开始(一直到第一个节点)调用维护堆的函数,即可根据输入数组建立一个最大堆。

/**
 * 建堆,nums[0]表示第堆的大小
 * 
 * 
 */
void buildMaxHeap(int nums[]){
    for(int i=nums[0]/2;i>0;i--){
        maxHeapIfy(nums,i);
    }
}

4. 测试

4.1 测试代码

#include<stdio.h>
#include"tools.h"
#include"tets.h"
int main(){
    int s[]={0,2,7,2,9,100,3,6};
    s[0] = sizeof(s)/sizeof(s[0])-1;
    
    printf("原始堆顺序如下:\n");
    for(int i = 1;i<8;i++){
        printf("%d  ",s[i]);
    }
    printf("\n堆的大小为:%d \n",s[0]);

    buildMaxHeap(s);

    int flag = maxHeapIfy(s,1);

    printf("flag:%d \n",flag);

    printf("排序后的堆顺序如下:\n");
    for(int i = 1;i<8;i++){
        printf("%d  ",s[i]);
    }
    return 0;
}

4.2 测试结果

在这里插入图片描述

5. 时间复杂度

维护堆时间复杂度: O ( log ⁡ n ) = O ( h ) O(\log n)=O(h) O(logn)=O(h) h h h即待维护节点的高度)
建堆时间复杂度: O ( n ) O(n) O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是鱼不是魚

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

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

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

打赏作者

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

抵扣说明:

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

余额充值