十大排序之堆排序

堆排序算法就是在根节点与孩子节点比较大小,然后交换之前的值。堆排序利用来二叉树的性质,而这个树是一种特殊的树完成二叉树。堆排序分为大堆和小堆。
大堆定义:每个根节点的值都大于左孩子和右孩子的值。大堆排序是升序的,值是从小到大的排序方式
性质: array[i] > array[2 * i + 1] && array[i] > array[2 * i + 2]
小堆定义:每个根节点的值都小于左孩子和右孩子的值。小堆排序是降序的,值是从大到小的排序方式
性质 array[i] < array[2 * i + 1] && array[i] < array[2 * i + 2]
思路:
1、先构造大堆。
2、将顶堆元素与末尾元素进行交换
3、重复第二步骤,得到一个有序的数组。

void Head(int* arr, int i, int len) { // 记录当前i为最大值
    int left_child = 2 * i + 1; 
    while (left_child < len) {
        //建立大堆,若左孩子小于右孩子,取值为右孩子的下标,右孩子再与父结点比较
        if (left_child + 1 < len && arr[left_child] < arr[left_child + 1]) { 
            left_child ++; // 在构建的时候确保左孩子小于右孩子,并取右孩子的下标
        }
        //将左右孩子中,数值最大的与父结点进行比较,若孩子结点比父结点小,说明父结点的数值比左右孩子都大,不需要交换
        if (arr[i] > arr[left_child]) {
            break; //说明该父结点和其孩子结点调整结束,退出循环,从下一个父结点调整
        }
        Swap(arr, i, left_child);
        //交换之后,要考虑结点与自己的孩子结点的数值比较,还要进行调整,将当前父节点换成孩子结点所在位置
        i = left_child;
        left_child = 2 * i + 1;
    }
}
void CreateHead(int *arr,int len) {
    int i;
    for(i = len / 2 - 1; i >= 0; i--) {
        Head(arr, i, len);
    }
}
void HeapSort(int* arr, int len) {
    int i;
    CreateHead(arr, len);
    for (i = len - 1; i > 0; i--) {  //进行n-1趟排序
        Swap(arr, 0, i); // 跟与最后一个元素交换
       // 对调整  自上而下
        len --;
        Head(arr, 0, len);
    }
}
int main(int argc, char **argv)
{
    int len = 10;
    int array[10];
    int i;
    srand(time(NULL));
    for (i = 0; i < len; i++) { // 采用随机数,参数数组的值。
        array[i] = rand() / 100;
    }
    printf("Before sorting \r\n");
    for (i = 0; i < len; i++) {
        printf("%d ", array[i]);
    }
    printf("\r\n");
    HeapSort(array, len);
    printf("After sorting \r\n");
    for (i = 0; i < len; i++) {
        printf("%d ", array[i]);
    }
    return 0;
}

执行完毕之后的结果
在这里插入图片描述
对代码进行改进,利用三个数比较的原理,谁是最大的那个。

void Head(int* arr, int i, int len) {   
    int left_child = 2 * i + 1; // 左孩子
    int right_child = 2 * i + 2; // 右孩子
    int max = i; //将当前设置为最大得根节点
    while ( left_child < len) {
        if ( left_child < len && arr[left_child] > arr[max]) { // 将左孩子与根相比较,取最大的一个
            max = left_child;
        }
        if ( right_child < len && arr[right_child] > arr[max]) { // 将右孩子与根相比较,取最大的一个
            max = right_child;
        }
        if (arr[max] < arr[i]) { // 左右孩子有一个是最大的,在和根节点相比较取最大值。
            i = max;
        }
        if (i == max) { // 若根节点为最大,说明已经满足大堆。
            break;
        }
        Swap(arr, max, i); // 若根节点不是最大,则交换值
        i = max;
        // 要调整左右孩子的下标值
        left_child = 2 * i + 1;
        right_child = 2 * i + 2;
    }
} 

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可厉害的土豆

你的鼓励是我创作的源泉

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

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

打赏作者

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

抵扣说明:

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

余额充值