堆的性质(大根堆):父节点大于左右儿子
堆排序
-
建堆
-
每次拿堆顶元素和末尾 i 进行交换(相当于 i~n 都是排好序的)。交换后堆顶破坏了堆的性质,把它堆化。
建堆
从最后一个非叶子节点 r 开始,对它记性 s i f t D o w n ( r ) siftDown(r) siftDown(r) 操作,也就是如果它的儿子比它大就交换。如果交换后破坏了儿子为根的堆,那么向下递归。
//siftDown操作相当于维护以r为根的堆
void siftDown(vector<int>& nums, int r, int tail){
while(leftChild(r)<=tail){
int biggerId = leftChild(r);
if(rightChild(r)<=tail && nums[leftChild(r)]< nums[rightChild(r)]){
biggerId = rightChild(r);
}
if(nums[r] >= nums[biggerId]) //该节点稳定了
break;
swap(nums,r,biggerId);
r = biggerId;
}
}
//从最后一个非叶子节点开始,依次调整以i为根的堆
void buildHeap(vector<int>& nums){
int last = nums.size()-1;
for(int i = last/2;i>=0;i--){
siftDown(nums,i,last);
}
}
建堆后的排序
每次交换n-1-i和堆顶,然后调整0位根的堆
void sortAfterBuild(vector<int>& nums){
for(int i=0;i<nums.size();i++){
int last = nums.size() - i-1;
swap(nums,0,last);
siftDown(nums,0,last-1);
}
}