2堆排序 不稳定 快速 适合海量数据
利用堆的数据结构来排序(参见堆博客)
堆是一种优先队列,两种实现,最大堆和最小堆,这里先讲解最大堆(以下简称堆),堆是一个完全二叉树,根节点要永远保持最大,大于子节点,所以一旦堆内数据发生变化,要重建堆
堆排的步骤:
- 建堆,最大堆或者最小堆
- 堆顶元素跟堆尾元素互换
- 堆尺寸-1,继续调整成最大堆
- 重复,知道堆大小为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 就是用的堆排,(待补充)