堆排序基本思路
1、理解堆的特点,父节点总是大于(在总是小于)孩子节点。
父节点总是大于孩子节点的完全二叉树称为大根堆。(本文以大根堆为例)
父节点总是小于孩子节点的完全二叉树称为小根堆。
2、每次把堆的最上面的值拿出来,再调整余下节点为新的堆。
3、拿n-1次后则完成排序。
heapSort初步实现:
1、建堆
2、取顶
3、调整
重复2、3的步骤n-1次完成排序
void heapSort(vector<int>&vec){
createHeap(vec);
for(int loc=vec.size()-1;loc>0;--loc){
swap(vec[loc],vec[0]);
adjustHeap(vec,0,loc-1);
}
}
剩下的那么接下来的问题就是如何建堆和调整堆。
如何建堆
思路:
1、叶子节点没子节点,可视作堆。完全二叉树最后一层叶子数为总个数的1/2或1/2-1;
2、则需要从第一个叶子节点的前一个节点开始调整,以每个节点为顶点的堆。设这节点为s
,即已有[s+1,s+2.....n]
是已完成的堆,
3、调整s
到根节点的每一个节点则完成堆的建立
createHeap实现
void createHeap(vector<int>&vec){
unsigned size=vec.size();
for(int i=size/2-1;i>=0;--i)
adjustHeap(vec,i,size-1);
}
如何调整堆
思路:
1、与两个子节点中最大的数比大小
2、如果大于两个子节点,则已完成调整。(因为调整堆,是已有【s+1…n】堆基础)
3、如果小于子节点,则与子节点互换位置,重复上面的过程。
调整堆实现
void adjustHeap(vector<int>&vec,int i,int loc){
for(int j=2*i+1;j<=loc;j=j*2+1)
{
if(j<loc&&vec[j]<vec[j+1]) j++;
if(vec[j]<=vec[i]) break;
swap(vec[j],vec[i]);i=j;
}
}
附录( 包括测试的主函数的完整代码)
#include<iostream>
#include<vector>
using namespace std;
void adjustHeap(vector<int>&vec,int i,int loc){
for(int j=2*i+1;j<=loc;j=j*2+1)
{
if(j<loc&&vec[j]<vec[j+1]) j++;
if(vec[j]<=vec[i]) break;
swap(vec[j],vec[i]);i=j;
}
}
void createHeap(vector<int>&vec){
unsigned size=vec.size();
for(int i=size/2-1;i>=0;--i)
adjustHeap(vec,i,size-1);
}
void heapSort(vector<int>&vec){
createHeap(vec);
for(int loc=vec.size()-1;loc>0;--loc){
swap(vec[loc],vec[0]);
adjustHeap(vec,0,loc-1);
}
}
int main(){
vector<int>vec={65,66,55,33,22,10,22,1,3,5,7,3,4,2,0,4,3,2,8,7,6};
heapSort(vec);
for(int val:vec)
cout<<val<<" ";
cout<<endl;
}