堆排序(C++)

堆排序是十大排序算法(插入,冒泡,选择,希尔,归并,快排,堆,计数,桶,基数)中的一种,而看了看C++标准库里面的sort函数中是依据状态进行选择哪一种排序,例如对数据先进行快排,快排分成了小数据的时候使用插入,快排递归过深时选择堆排序。总共有插入,快排,堆排。堆排序的重要性不言而喻了吧。插入排序就不说了,接下来主要比较快排和堆排序。

堆排序的时间复杂度与数组的初始状态是无关的!即堆排序的最好,最坏和平均时间复杂度都是O(nlogn),也就是这点跟快排不同,快排平均时间复杂度为O(nlogn)(都是nlogn但是各系数不同,快排通常更快),在最坏(数组正序)的情况下复杂度会达到O(n^2)。

堆排序无需额外的空间,所以空间复杂度是O(1),而快排的空间复杂度是O(logn)且会存在递归过深导致的内存溢出。

说了堆排序的性质,来看看堆排序的概念及过程吧。

堆排序是基于完全二叉树的结构来进行排序的,但是实际是存储在数组当中,说着怪怪的,看了代码就懂了。堆分为大根堆与小根堆,大根堆就是每个节点都大于他的子节点。

首先塞入无序待排序的数组,实际数组数据结构为:

int arr[] = {91,60,96,13,35,65,46,65,10,30,20,31,77,81,22};

但是我们要理解成下图:

  图源于1.7 堆排序 | 菜鸟教程,刚好建立完成大根堆的过程图,后面的图也是基于此。

 

堆排序总体流程:

(1)初始化,将无序的数组从下到上建立成堆(此为大根堆)

(2)将堆顶(96)与最后一个节点(22)交换位置,最后一个节点(96)弹出(也可以理解成,将堆顶弹出,让最后一个节点接替堆顶)。堆顶数(22)再从上到下交换移动下去。

 

也就是说我们需要实现的功能其实就两点,一步是从下到上建堆,一步是堆顶与最后一节点交换后再重新调整使之符合大根堆。上代码(代码基于菜鸟教程):

#include <iostream>
#include <algorithm>
using namespace std;
 
void max_heapify(int arr[], int start, int end)//此函数是判断大小并执行交换 
{
    int dad = start;//获取父节点的下标 
    int son = dad * 2 + 1;//左节点,因为下标0开始所以需要+1
    while (son <= end)  //子节点不能超出范围,就是判断若无子节点直接退出 
    {    
        if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的 
            ++son;//指向右节点 
        if (arr[dad] > arr[son]) //如果父节点大于子节点代表调整完毕,直接跳出函数
            return;
        else  //否则交换父子节点再继续子节点和孙节点比较
        {
            swap(arr[dad], arr[son]);
            dad = son;//父节点指向子节点 
            son = son * 2 + 1;//子节点指向孙节点 ,也就是这个点还需要跟孙节点进行比较
        }
    }
}
 
void heap_sort(int arr[], int len) 
{
    //初始化,i从最后一个父节点开始调整,从46开始 ,也就是从下到上进行调整,
    for (int i = len / 2 - 1; i >= 0; --i)//15个元素,最后一个父节点下标是6
        max_heapify(arr, i, len - 1);//数组下标是0-14,所以end是len-1 
    //执行到这一步就已经符合大根堆的结构了 
    //使顶堆跟最后一个元素交换,这里--i达到弹出的效果,也就是i+1到len-1的范围都是已经排好序的,再重新调整使符合大根堆,直到排序完毕
    for (int i = len - 1; i > 0; --i) 
    {
        swap(arr[0], arr[i]);
        max_heapify(arr, 0, i - 1);
    }
}
 
int main() 
{
    int arr[] = {91,60,96,13,35,65,46,65,10,30,20,31,77,81,22};//15个元素,数组下标是0-14 
    int len = (int) sizeof(arr) / sizeof(*arr);//获取数组元素个数 
    heap_sort(arr, len);
    for (int i = 0; i < len; ++i)
        cout << arr[i] << ' ';//输出排序后的数组,debug看一眼 
    cout << endl;
    system("pause");
}

两个函数,max_heapify()调整堆,heap_sort()堆排序,

heap_sort()内就两个步骤,建立大根堆,弹出最大值并调整大根堆。具体实现看看代码注释吧。

执行结果为:

10 13 20 22 30 31 35 46 60 65 65 77 81 91 96

当然,从结果上可看不出堆排序的过程和优势,还是得理解过程才能体现出区别。

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是堆排序的C++代码: ```c++ #include <iostream> using namespace std; void heapify(int arr[], int n, int i) { int largest = i; int l = 2*i + 1; int r = 2*i + 2; if (l < n && arr[l] > arr[largest]) largest = l; if (r < n && arr[r] > arr[largest]) largest = r; if (largest != i) { swap(arr[i], arr[largest]); heapify(arr, n, largest); } } void heapSort(int arr[], int n) { 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]); heapify(arr, i, 0); } } void printArray(int arr[], int n) { for (int i = 0; i < n; ++i) cout << arr[i] << " "; cout << "\n"; } int main() { int arr[] = {12, 11, 13, 5, 6, 7}; int n = sizeof(arr)/sizeof(arr[0]); cout << "Original array: "; printArray(arr, n); heapSort(arr, n); cout << "Sorted array: "; printArray(arr, n); } ``` 这段代码中包含了两个函数:`heapify` 和 `heapSort`。 `heapify` 函数将给定的数组中的元素进行堆化,即将元素按照一定规则构建成最大堆或最小堆。这里使用的是构建最大堆的方式。`heapify` 函数的时间复杂度为 O(log n)。 `heapSort` 函数则是堆排序的主要实现。首先,它将给定的数组进行堆化,然后将堆顶元素(即最大值或最小值)与堆底元素进行交换,并将堆大小减 1。接着,它再次对堆进行堆化,重复上述步骤直至堆为空。`heapSort` 函数的时间复杂度为 O(n log n)。 最后,`printArray` 函数用于打印排序后的数组。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值