堆结构和堆排序

堆结构和堆排序

1)基本思想:
1.堆结构:利用数组来模拟堆(以完全二叉树形式构造),用数组下标充当堆的节点位置,并用一个变量size表示堆的大小
2.堆排序:利用大根堆,通过将根节点的数和最后一个节点的数交换位置,可以将最大数排到最后面,然后再对堆进行调整,使其重新变成大根堆,通过不断操作,完成排序
2)代码实现:

#include<iostream>
using namespace std;

// 堆结构和堆排序 (以大根堆为例)
// 用数组来模拟堆,size代表堆的大小,数组下标可以代表根和左右孩子的位置
/*
                    0
            1               2
        3       4       5       6
*/
// 如果一个节点 为 i, 那么他的父节点就为 (i-1)/2(向下取整),左孩子就为 i*2+1,右孩子为i*2+2;


// 交换数组中两个元素的位置
void swap(int arr[],int idx1,int idx2){
    int temp = arr[idx1];
    arr[idx1] = arr[idx2];
    arr[idx2] = temp;
}


// i 位置的数 向上调整大根堆,令任意子树都满足 根节点 > 左右孩子
void heapInsert(int arr[],int i){

    // 一直与父节点比较,当小于等于父节点或者没有父节点时退出
    while(arr[i] > arr[(i-1)/2] && i != 0){
        //如果比父节点大,就交换位置
        swap(arr,i,(i-1)/2);
        // 更新i的位置
        i = (i-1)/2;
    }
} 

// i 位置的数 向下调整大根堆,当前堆的大小为size
void heapify(int arr[],int i,int size){
    //左孩子位置
    int l = i*2+1;

    //判断是否有左孩子
    while(l<size){
        // 判断是否存在右孩子,如果存在,判断左右孩子哪个大,并记录较大的那个孩子的下标
        int best = l+1 < size && arr[l+1] > arr[l] ? l+1 : l;
        
        // 判断大孩子是否比父亲大,如果小于等于父亲,就令best = i;
        best = arr[best] > arr[i] ? best : i; 

        // 孩子不够强,不用调整了,直接break
        if(best == i){
            break;
        }

        // 交换位置,并且更新i的位置
        swap(arr,best,i);
        i = best;
        l = i*2+1;
    }
}

// 堆排序 时间复杂度为 O(nlogn)
// 思路: 先构造大根堆,然后再让根节点与最后一个节点交换位置,这样最后一个数就是最大的
// 然后进行 size-- 并且向下调整(heapify函数),再次形成大根堆,再交换,直到所有数都排完
// 从顶到底建堆 时间复杂度为 O(nlogn)
void heapSort1(int arr[],int len){

    for(int i = 0;i<len;i++){
        heapInsert(arr,i);
    }
    int size = len;

    while(size > 1){
        // 将根结点和 最后一个数交换,
        swap(arr,0,--size);
        //向下调整,重新形成大根堆
        heapify(arr,0,size);
    }
}

// 从底到顶建堆 时间复杂度为 O(n)
void heapSort2(int arr[],int len){
    for(int i = len - 1;i>=0;i--){
        heapify(arr,i,len);
    }
    int size = len;

    while(size > 1){
        swap(arr,0,--size);
        heapify(arr,0,size);
    }

}

int main(){

    int n;
    cin >> n;
    int arr[100];
    for(int i = 0;i<n;i++){
        cin >> arr[i];
    }

    heapSort2(arr,n);

    for(int i = 0;i<n;i++){
        cout << arr[i] << " ";
    }


    return 0;
}

3)总结:时间复杂度为O(nlogn),非常高效

4.15补充

1)STL库中构建堆的方法:

#include <iostream>
#include <vector>
#include <algorithm> // 堆算法所在的头文件

int main() {
    std::vector<int> vec = {10, 20, 5, 60};

    // 1. 构建大顶堆 (默认)
    std::make_heap(vec.begin(), vec.end());
    std::cout << "大顶堆的堆顶: " << vec.front() << std::endl; // 输出: 60

    // 2. 构建小顶堆
    std::make_heap(vec.begin(), vec.end(), std::greater<int>());
    std::cout << "小顶堆的堆顶: " << vec.front() << std::endl; // 输出: 5

    // 3. 添加元素
    vec.push_back(100); // 先添加到末尾
    std::push_heap(vec.begin(), vec.end(), std::greater<int>()); // 再调整堆
    std::cout << "添加100后小顶堆的堆顶: " << vec.front() << std::endl; // 输出: 5

    // 4. 删除元素
    std::pop_heap(vec.begin(), vec.end(), std::greater<int>()); // 将堆顶移到末尾
    vec.pop_back(); // 真正删除末尾元素
    std::cout << "删除后小顶堆的堆顶: " << vec.front() << std::endl;

    return 0;
}

posted on 2026-04-10 16:53  Sean2299  阅读(11)  评论(0)    收藏  举报

导航