排序算法之堆排序

2堆排序 不稳定 快速 适合海量数据

利用堆的数据结构来排序(参见堆博客)

堆是一种优先队列,两种实现,最大堆和最小堆,这里先讲解最大堆(以下简称堆),堆是一个完全二叉树,根节点要永远保持最大,大于子节点,所以一旦堆内数据发生变化,要重建堆

堆排的步骤:

  1. 建堆,最大堆或者最小堆
  2. 堆顶元素跟堆尾元素互换
  3. 堆尺寸-1,继续调整成最大堆
  4. 重复,知道堆大小为1

所以根据以上步骤我们可以写出四个函数

void swapHeapTop(vector<int>& v, int i, int j )//交换堆顶元素

void Heapify(vector<int> &v, int i, int size)//调整堆,比较父子节点哪个最大,把最大的放大父节点

int BuildHeap(vector<int>& v, int n)//建堆
    
void HeapSort(vector<int> &v, int n)//从第一个不是叶子节点的节点开始调整堆

堆漂亮的特性是能够用一个数组来表示一个堆,不需要指针

最大堆是指根节点大于等于左子树也大于等于右子树,适用于升序,因为最先出来的是最大的,最后出来的是最小的,那么最小的就在前面,最大的就在后面,所以是升序

同样的,小根堆适合降序

#include<iostream>
#include<vector>

using namespace std;

void swapHeapTop(vector<int>& v, int i, int j )
{
    int temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}
void Heapify(vector<int> &v, int i, int size)
{
    int left_child = 2*i +1;
    int right_child = 2*i +2;
    int max = i;//选出最大值
    if(left_child < size && v[left_child] > v[max])//如果左孩子大于max,那么最大的就是左孩子
    {
        max = left_child;
    }
    if(right_child < size && v[right_child] > v[max])
    {
        max = right_child;
    }
    if(max != i)
    {
        swapHeapTop(v,i,max);//把最大的节点换到堆顶
        Heapify(v,max,size);//继续调整
    }
}

int BuildHeap(vector<int>& v, int n){//建堆的时间复杂的O(n)
    int heapSize = n;
    for(int i = ((heapSize/2)-1); i >= 0; i--)//对于完全平衡的二叉树,最后一层的叶子节点从左往右排,
    //对于叶子结点不需要调整,不考虑,从有孩子节点的节点开始,所以是heapSize/2,-1是因为下标从0开始的
    {
        Heapify(v,i,heapSize);
    }
    return heapSize;
}

void HeapSort(vector<int> &v, int n)
{
    int heapSize = BuildHeap(v, n);//建立一个最大堆,求升序
    while ((heapSize > 1))
    {
        swapHeapTop(v,0, --heapSize);//将堆顶元素与堆最后一个元素互换,并把堆的尺寸-1
        Heapify(v, 0, heapSize);//调整堆
    }
}
int main()
{
    vector<int> v;
    v.push_back(100);
    v.push_back(33);
    v.push_back(3);
    v.push_back(7);
    v.push_back(11);
    v.push_back(6);
    v.push_back(8);
    v.push_back(5);
    HeapSort(v,v.size());
     for(auto c : v)
    {
        cout << c<< " ";
    } 
    return 0;
}

面试中常问的大数据场景题top K 就是用的堆排,(待补充)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值