Cyber骇客的层级霸权——【优化算法】之【排序算法】堆排序

⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///


WARNING : DETECTING HIGH ENERGY

🌊 🌉 🌊 心手合一 · 水到渠成

|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| >>> ACCESS TERMINAL <<< ||
| 🦾 作者主页 | 🔥 C语言核心 |
| 💾 编程百度 | 📡 代码仓库 |


Running Process: 100% | Latency: 0ms


索引与导读

"堆"数据结构的复习

🔗Lucy的空间骇客裂缝:堆

  • 什么是"堆" (Heap)?

    堆通常是一个可以被看做一棵完全二叉树的数组对象,也就是二叉树的顺序存储

    • 逻辑上:它是一棵完全二叉树
    • 物理上 :它存储在一个连续的数组中
  • 大顶堆与小顶堆

    • 大顶堆 (Max Heap) :每个节点的值都大于或等于 其左右孩子节点的值。
      • 数学定义 : a r r i ≥ a r r 2 i + 1 arri \ge arr2i+1 arri≥arr2i+1 且 a r r i ≥ a r r 2 i + 2 arri \ge arr2i+2 arri≥arr2i+2
      • 特性 :堆顶元素(数组首元素)是整个序列中的最大值
    • 小顶堆 (Min Heap) :每个节点的值都小于或等于 其左右孩子节点的值。
      • 特性 :堆顶元素是整个序列中的最小值
  • 数组下标与树的关系

    对于数组中任意位置 i i i 的元素(从0开始索引),其在逻辑二叉树中的关系如下:

    • 父节点 (Parent) 的下标: ⌊ ( i − 1 ) / 2 ⌋ \lfloor (i - 1) / 2 \rfloor ⌊(i−1)/2⌋
    • 左孩子 (Left Child) 的下标: 2 × i + 1 2 \times i + 1 2×i+1
    • 右孩子 (Right Child) 的下标: 2 × i + 2 2 \times i + 2 2×i+2

注意 :我们在进行升序排序 (从小到大)时,通常使用大顶堆 ;进行降序排序时,使用小顶堆


堆排序的核心逻辑

堆排序主要分为两个核心阶段:

  1. 建堆 (Build Heap) :将一个无序数组调整为一个大顶堆 或者小顶堆
    • 升序:建大堆
    • 降序:建小堆
  2. 排序 (Sort)
    建堆和堆删除中都用到了向下调整 ,因此掌握了向下调整,就可以完成堆排序
    • 堆顶元素(最大值)数组末尾元素交换。
    • 将数组长度减 1(排除已排序的末尾元素)。
    • 对剩下的元素重新进行向下调整 ,使其再次满足大顶堆性质。
    • 重复上述过程,直到堆的大小为 1

堆排序 Heap Sort
核心基础
向下调整 Downward Adjustment
注: 建堆和排序的关键通用技术
第一阶段: 建堆 Build Heap
描述
将无序数组调整为堆结构
策略选择
升序排序
--> 建大顶堆 Max-Heap
降序排序
--> 建小顶堆 Min-Heap
第二阶段: 排序循环 Sorting Loop
前提: 已建成大顶堆/小顶堆
循环步骤

  1. 交换 Swap 堆顶最大值 <--> 数组末尾元素
  2. 缩小范围 Reduce Scope 数组有效长度减 1, 排除已排序元素
  3. 恢复堆性 Restore 对剩余元素重新向下调整
    终止条件
    循环直到堆大小 = 1

向下调整的算法

本次代码将综合堆数据结构 来实现

🔗Lucy的空间骇客裂缝:gitee码云的堆

c 复制代码
void AdjustDown(HP* php, int parent) {
    assert(php);
    int child = parent * 2 + 1; // 默认先指向左孩子
    while (child < php->size) {
        // 1. 在左右孩子中选出更"优"的一个
        if (child + 1 < php->size && php->cmp(php->arr[child + 1], php->arr[child])) {
            child++;
        }
        // 2. 如果选出的孩子比父节点更"优",则交换
        if (php->cmp(php->arr[child], php->arr[parent])) {
            Swap(&php->arr[child], &php->arr[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else {
            break;
        }
    }
}

🔥🔥🔥🔥代码解析

函数声明
void AdjustDown(HP* php, int parent)

  • HP* php:指向堆结构的指针
  • int parent:开始调整的父节点索引
  • 用于将parent节点调整到合适位置,保持堆的性质

计算左孩子索引
int child = parent * 2 + 1

  • 堆是完全二叉树,通常用数组存储

  • 数组下标从0开始的父子关系公式:

    • 左孩子 = 父节点 × 2 + 1

    • 右孩子 = 父节点 × 2 + 2

  • 这里先假设左孩子是需要比较的孩子


循环条件
while (child < php->size)

  • 只要child索引在堆的有效范围内就继续循环

选择更"优"的孩子
if (child + 1 < php->size && php->cmp(php->arr[child + 1], php->arr[child])) {child++;}

  1. child + 1 < php->size:检查右孩子是否存在
  • 如果child+1小于size,说明有右孩子
  1. php->cmp(php->arr[child + 1], php->arr[child]):
  • 调用比较函数比较右孩子和左孩子

  • 这个比较函数决定了是最大堆 还是最小堆

    • 最大堆:返回a > b
    • 最小堆:返回a < b
  • 如果右孩子更"优"(在大顶堆中更大,在小顶堆中更小),则child++指向右孩子

经过这个判断,child指向左右孩子中更"优"的那个


与父节点比较并交换

  1. 比较选出的孩子和父节点

    • 如果孩子更"优"(需要交换)
  2. 交换父节点和孩子节点的值

    • Swap函数交换两个元素
  3. 更新索引,继续向下调整

    • parent = child:父节点下移到刚才交换的位置

    • child = parent * 2 + 1:重新计算新的左孩子索引

    • 继续下一轮循环


堆排序代码实现

本次代码将综合堆数据结构 来实现

🔗Lucy的空间骇客裂缝:gitee码云的堆

注意编写前需要在头文件进行声明!

c 复制代码
void HeapSort(int* a, int n) {
    // 1. 建大堆 (从最后一个非叶子节点开始)
    for (int i = (n - 1 - 1) / 2; i >= 0; i--) {
        AdjustDown(a, n, i);
    }

    // 2. 交换与调整
    int end = n - 1;
    while (end > 0) {
        Swap(&a[0], &a[end]); // 将堆顶最大元素换到数组末尾
        AdjustDown(a, end, 0); // 在剩余 [0, end-1] 范围内向下调整
        end--;
    }
}

建堆阶段
(n - 1 - 1) / 2

  • 最后一个非叶子节点的索引公式:(最后一个元素索引 - 1) / 2

排序阶段
Swap(&a[0], &a[end]);

  • 将堆顶最大元素换到数组末尾

AdjustDown(a, end, 0)

  • 在剩余[0, end-1]范围内向下调整

🔨关于测试堆排序的分文件代码

🔗Lucy的空间骇客裂缝:gitee码云的堆排序


💻结尾--- 核心连接协议

警告: 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠


【📡】 建立深度链接: 关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。

【⚡】 能量过载分发: 执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。

【💾】 离线缓存核心: 将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。

【💬】 协议加密解密:评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。

【🛰️】 信号频率投票: 通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。



相关推荐
8Qi89 小时前
回文子串(Palindromic Substrings)—— 题解
算法·leetcode·职场和发展·动态规划
xskukuku9 小时前
使用VSCode配置C语言运行环境
c语言·ide·vscode
小宋加油啊13 小时前
机械臂抓取物体 PVN3D算法调研学习
学习·算法·3d
lqqjuly13 小时前
前沿算法深度解析(一)
算法
小欣加油14 小时前
leetcode1926 迷宫中离入口最近的出口
数据结构·c++·算法·leetcode·职场和发展
星恒随风15 小时前
C++ 类和对象入门(五):初始化列表、explicit 和 static 成员详解
开发语言·c++·笔记·学习·状态模式
浪客灿心15 小时前
项目篇:模块设计与实现
数据库·c++
牛油果子哥q15 小时前
【C++ STL vector】C++ STL vector 终极精讲:动态数组底层原理、两倍扩容机制、迭代器失效、增删查改、性能剖析与工程避坑指南
开发语言·c++
happymaker062616 小时前
LeetCodeHot100——42.接雨水
算法