C++中堆排序详解

什么是堆?

堆(Heap)是一种特殊的完全二叉树结构,它通常被用作优先队列的实现,或者是在实现如堆排序这样的算法时用到。堆有两种主要的类型:最大堆(Max Heap)和最小堆(Min Heap)。

完全二叉树:除了最后一层外,每一层都被完全填满,并且所有节点都尽可能地向左对齐。也就是说,除最后一层外,所有层均为满层。最后一层,所有节点的排布都要靠左,直至排满。(个人理解)。

最大堆:每个父节点的值都大于其子节点的值。(所有父亲都比儿子大)根节点最大

最小堆:每个父节点的值都小于其子节点的值。(所有父亲都比儿子小)根节点最小

假装有图

C++中堆的实现

        C++中,标准库并没有直接提供堆的数据结构。可以利用优先队列实现最大堆和自己手动创建堆

使用std::priority_queue

        在C++中,标准库并没有直接提供堆的数据结构,但是提供了std::priority_queue,它底层默认使用最大堆实现。

#include <iostream>//用于输入输出操作
#include <queue>
#include <vector>

int main() {
    // 创建一个最大堆(priority_queue 默认为最大堆)
    std::priority_queue<int> maxHeap;
     //采用std::greater<int>,可以将priority_queue 转换为最小堆
    // std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;

    // 向堆中插入元素,插入后,堆会自动维护最大堆的性质
    maxHeap.push(10);
    maxHeap.push(5);
    maxHeap.push(20);
    maxHeap.push(15);

    // 输出并删除堆顶元素(最大元素)
    std::cout << "Heap elements in descending order:" << std::endl;

    //通过 while 循环遍历并输出堆中的元素,堆顶元素最大,
    //每次 pop 操作后堆顶会更新为下一个最大元素。
    while (!maxHeap.empty()) {
        std::cout << maxHeap.top() << " "; // 输出堆顶元素
        maxHeap.pop(); // 删除堆顶元素
    }
    std::cout << std::endl;

    return 0;
}

手动实现堆

#include <iostream>
#include <vector>
#include <algorithm> // For std::swap

class MaxHeap {
public:
    MaxHeap() {}

    // 插入元素
    void insert(int value) {
        heap.push_back(value);
        heapifyUp(heap.size() - 1);
    }

    // 删除最大元素(堆顶)
    void extractMax() {
        if (heap.empty()) {
            std::cout << "Heap is empty!" << std::endl;
            return;
        }

        // 替换堆顶元素
        heap[0] = heap.back();
        heap.pop_back();

        // 调整堆
        heapifyDown(0);
    }

    // 打印堆内容
    void printHeap() const {
        for (int val : heap) {
            std::cout << val << " ";
        }
        std::cout << std::endl;
    }

private:
    std::vector<int> heap;

    // 向上堆化
    void heapifyUp(int index) {
        while (index > 0) {
            int parent = (index - 1) / 2;
            if (heap[index] > heap[parent]) {
                std::swap(heap[index], heap[parent]);
                index = parent;
            } else {
                break;
            }
        }
    }

    // 向下堆化
    void heapifyDown(int index) {
        int size = heap.size();
        int largest = index;
        int left = 2 * index + 1;
        int right = 2 * index + 2;

        if (left < size && heap[left] > heap[largest]) {
            largest = left;
        }

        if (right < size && heap[right] > heap[largest]) {
            largest = right;
        }

        if (largest != index) {
            std::swap(heap[index], heap[largest]);
            heapifyDown(largest);
        }
    }
};

C++中堆排序的实现

        需要明确的是,堆本身是具有排序的。下面我们, 以最大堆为例子,其父节点的值大于等于其子节点的值。因此堆排序,只需要进行最大堆的重复建立,然后不断将堆顶元素(最大)与末尾元素交换并重新调整堆,使得数组逐渐有序,直到排序完成。(堆可以利用数组建立)。

  • 堆排序的时间复杂度为O(nlogn),n为取出元素,logn为建立堆的时间,所以是nlongn。
  • 堆排序是一种原地排序算法,不需要额外的存储空间,只需要交换值。

下面是具体实现步骤:

        首先是实现值交换

viod swap(int&a,int&b){
    int temp;
    temp=a;
    a =b;
    b=temp;
}

      之后是构建最大堆(这个上面已经讲过了)

// 辅助函数,用于下沉调整,保持最大堆的性质  
void heapify(vector<int>& arr, int n, int i) {  
    int largest = i; // 初始化最大值为根  
    int left = 2 * i + 1; // 左子节点  
    int right = 2 * i + 2; // 右子节点  
    //这里有一点强调的是,数组构建的堆中,父节点为i,左节点为2i+1,右节点为2i+2.
    //后面只需要判断父子节点的大小就行

    // 如果左子节点大于根节点  
    if (left < n && arr[left] > arr[largest]) {  
        largest = left;  
    }  
  
    // 如果右子节点是最大值  
    if (right < n && arr[right] > arr[largest]) {  
        largest = right;  
    }  
  
    // 如果最大值不是根节点,则交换  
    if (largest != i) {  
        swap(arr[i], arr[largest]);  
  
        // 递归地调整受影响的子树  
        heapify(arr, n, largest);  
    }  
} 

        最后就是我们的堆排序算法了,首先是构建一个原始最大堆,之后就是遍历所有元素

// 堆排序函数  
void heapSort(vector<int>& arr) {  
    int n = arr.size();  
  
    // 构建最大堆  
    for (int i = n / 2 - 1; i >= 0; i--) {  
        heapify(arr, n, i);  
    }  
  
    // 一个个从堆顶取出元素  
    for (int i = n - 1; i > 0; i--) {  
        // 移动当前根到末尾  
        swap(arr[0], arr[i]);  
  
        // 调用max heapify在减少的堆上  
        heapify(arr, i, 0);  
    }  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值