堆排序
对于一个数组,总能用完全二叉树的方式去理解他,例如对于数组,
5 | 3 | 6 | 6 | 0 | 4 | 2 | 4 | 8 |
---|---|---|---|---|---|---|---|---|
可以表示为完全二叉树如下 |
1. 初始化堆
堆就是,root节点总是比他的两个子节点的值要大,从最后一个非叶子节点(len/2-1
)开始进行堆调整,本例是从第二个6开始,其下标正好也必然是len/2-1
,若发现其子节点有大于当前节点的,则将最大的子节点与当前节点进行交换,进行一步交换形成二叉树:
当然实际上是数组中数的值在改变。需要注意的是,在调整的过程中,如 上一个图,若3与8交换,则3的位置仍然需要进行堆调整,3再与6交换;经过一轮调整后,形成二叉树如下,
2. 交换堆顶和最后一个元素
由于是从小到大排序,所以最大元素放置最后,形成:
3. 再次进行堆调整
此时最后一个元素以符合要求,然后从二叉树的第一个元素,再开始进行堆调整,注意此时不要把最后已排好的元素算进来,否则8会重新升至顶.
代码
#include<iostream>
#include<vector>
#include<time.h>
using namespace std;
/*
pos 待调整的数组的节点位置
len 需要调整的最大下标,不是数组的实际长度,大于len下标表示是已经调整好的,无需再进行
*/
void heapadjust(vector<int> &nums, int pos,int len){
int index = pos;
int lchild = pos*2 + 1;
int rchild = pos*2 + 2;
if (lchild<len && nums[lchild]>nums[index])
index = lchild;
if (rchild<len && nums[rchild]>nums[index])
index = rchild;
if (index != pos){
swap(nums[index], nums[pos]);
heapadjust(nums, index,len);//若进行调整,则必须递归调整下面部分
}
}
void heapsort(vector<int> &nums){
int len = nums.size();
//1、初始化堆
for (int i = len/2 - 1; i >= 0; --i){//从最后一个非叶子节点开始调整堆
heapadjust(nums,i,len);//调整子节点值都小于root节点值
}
/* 此时最大元素已至堆顶 */
/* 2、交换堆顶(0)和最后元素(i)*/
for (int i = len-1; i >= 0; --i){
swap(nums[0], nums[i]);
heapadjust(nums, 0, i);//这里必须限制i,若不在i前截至,则已经放置最后的最大的元素会被重新放置堆顶
}
}
int main(){
srand((unsigned int)time(NULL));
//定义数组
vector<int> arr;
for (int i = 0; i < 10; ++i){
int num = rand() % 100;
arr.push_back(num);
}
heapsort(arr);
for (auto i : arr)
cout << i << ' ';
cout << endl;
system("pause");
return 0;
}