排序算法-堆排序(王道数据结构)

相关知识

叶结点(终端结点)与分支结点(非终端结点)

如果结点总数为n(结点编号从1开始计数),则

非终端结点:i <= ⌊n/2⌋
终端结点: i > ⌊n/2⌋

父节点、左孩子与右孩子

如果非终端结点编号为j,则:

左孩子编号:2j
右孩子编号:2j+1
父节点编号:⌊j/2⌋

大根堆与小根堆

大根堆:根 >= 左、右
小根堆:根 <= 左、右
二叉排序树(BST):左 <= 根 <= 右

算法思路

堆排序:

每一趟将堆顶元素加入有序子序列(与待排序序列中的最后一个元素交换),并将待排序序列元素再次调整为大根堆(小元素不断"下坠")
  • 基于大根堆的堆排序得到递增序列

  • 基于小根堆的堆排序得到递减序列

算法分析

  • 稳定性:不稳定

  • 时间复杂度:O(nlog2n)

  • 空间复杂度:O(1)

代码实现

// 建立大根堆
void BuildMaxHeap(int A[], int len) {
    for (int i = len / 2; i > 0; i--) { // 从最后一个非终端结点开始
        HeadAdjust(A, i, len);
    }
}

// 将以k为根的子树调整为大根堆
void HeadAdjust(int A[], int k, int len) {
    A[0] = A[k];                             // A[0]暂存子树的根结点
    for (int i = 2 * k; i <= len; i *= 2) {  // 沿key较大的子结点向下筛选
        if (i < len && A[i] < A[i + 1]) {
            i++;  // 取key子结点较大者的下标
        }
        if (A[0] >= A[i]) {
            break;  // 根key比左右子结点都大,无须调整
        } else {
            A[k] = A[i];  // 将A[i]调整到双亲结点上
            k = i;        // 修改k值,以便继续向下筛选
        }
    }
    A[k] = A[0];  // 被筛选结点的值放入最终位置
}

/**
 * 堆排序完整逻辑
 **/
void HeapSort(int A[], int len) {
    BuildMaxHeap(A, len);            // 初始建堆
    for (int i = len; i > 1; i--) {  // n-1趟交换和建堆过程
        swap(A[i], A[1]);            // 将堆顶元素和堆底元素交换
        HeadAdjust(A, 1, i - 1);     // 把剩余的待排序元素整理成堆
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值