C++堆排序

堆排序(Heap Sort)是一种基于二叉堆数据结构的比较排序算法,它是一种选择排序,可分为最大堆排序和最小堆排序,以下主要介绍最大堆排序。

堆排序的基本原理

  1. 二叉堆的定义

    • 最大堆:对于每个节点 i(除根节点外),都满足 A[parent(i)] >= A[i],即父节点的值大于或等于其子节点的值。
    • 最小堆:对于每个节点 i(除根节点外),都满足 A[parent(i)] <= A[i],即父节点的值小于或等于其子节点的值。
    • 对于数组 A 表示的堆,根节点为 A[0],对于索引为 i 的节点,其左子节点索引为 2 * i + 1,右子节点索引为 2 * i + 2,父节点索引为 (i - 1) / 2
  2. 堆排序的步骤

    • 首先将数组构建成一个最大堆(或最小堆)。
    • 交换堆顶元素(最大值或最小值)和堆的最后一个元素。
    • 缩小堆的范围,对堆顶元素进行下沉操作(sift down),使其满足堆的性质。
    • 重复上述步骤,直到堆的大小为 1。

C++代码实现

#include <iostream>
#include <vector>

// 辅助函数:交换两个元素
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

// 下沉操作,将元素放到合适位置,维护最大堆的性质
void siftDown(std::vector<int>& arr, int start, int end) {
    int root = start;
    while (2 * root + 1 <= end) {
        int child = 2 * root + 1;
        int swap_index = root;
        // 比较左子节点
        if (arr[swap_index] < arr[child]) {
            swap_index = child;
        }
        // 比较右子节点,如果存在且比当前最大的子节点大
        if (child + 1 <= end && arr[swap_index] < arr[child + 1]) {
            swap_index = child + 1;
        }
        // 如果需要交换
        if (swap_index!= root) {
            swap(arr[root], arr[swap_index]);
            root = swap_index;
        } else {
            return;
        }
    }
}

// 堆排序函数
void heapSort(std::vector<int>& arr) {
    int n = arr.size();
    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--) {
        siftDown(arr, i, n - 1);
    }
    // 逐个将堆顶元素移到末尾,并对堆顶元素进行下沉操作
    for (int i = n - 1; i > 0; i--) {
        swap(arr[0], arr[i]);
        siftDown(arr, 0, i - 1);
    }
}

// 打印数组元素
void printArray(const std::vector<int>& arr) {
    for (int val : arr) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
}


int main() {
    std::vector<int> arr = {12, 11, 13, 5, 6};
    std::cout << "Original array: ";
    printArray(arr);
    heapSort(arr);
    std::cout << "Sorted array: ";
    printArray(arr);
    return 0;
}

代码解释

  • swap 函数

    • 该函数用于交换两个元素的值,接受两个引用参数,使用一个临时变量来交换元素的值。
  • siftDown 函数

    • 该函数用于将堆中 start 位置的元素下沉到合适的位置,以保持最大堆的性质。
    • start 为要下沉元素的位置,end 为堆的最后一个元素的位置。
    • 首先将 root 设为 start 位置。
    • 计算 childroot 的左子节点(2 * root + 1)。
    • 比较 arr[swap_index]arr[child] 的大小,若 arr[child] 大,更新 swap_indexchild
    • 再比较 arr[swap_index]arr[child + 1](若存在)的大小,若 arr[child + 1] 大,更新 swap_index
    • swap_index 不等于 root,交换 arr[root]arr[swap_index] 的值,并更新 rootswap_index
  • heapSort 函数

    • 首先构建最大堆,从最后一个非叶子节点开始,依次对每个节点进行下沉操作,调用 siftDown 函数。
    • 构建好最大堆后,将堆顶元素(最大值)与堆的最后一个元素交换。
    • 对堆顶元素进行下沉操作,保持最大堆的性质。
    • 重复上述步骤,直到堆中只剩下一个元素。
  • printArray 函数

    • 该函数用于打印数组元素,遍历数组并输出元素值。

堆排序的时间复杂度

  • 堆排序的平均时间复杂度为 O ( n l o g n ) O(n log n) O(nlogn),因为构建堆的时间复杂度为 O ( n ) O(n) O(n),而交换堆顶元素和下沉操作的时间复杂度为 O ( l o g n ) O(log n) O(logn),需要执行 n 次。
  • 空间复杂度为 O ( 1 ) O(1) O(1),因为堆排序是原地排序,除了输入数组外,不需要额外的存储空间。

堆排序是一种高效的排序算法,尤其适用于处理大量数据的情况,它在性能上较为稳定,并且不需要额外的存储空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值