最近看面经总是看到手写堆排序的题,所以自己手写了一个堆排序。
主要有四个功能,建立堆,弹出堆顶元素,插入一个新元素,堆排序。
1:建立堆
找到第一个非叶子节点,和它的子节点比较。
假设有两个子节点,选取子节点中大的值,如果父节点比上面的值小,交换。
假设有一个子节点,选取右节点的值,如果父节点比上面的值小,交换。
然后顺着路径往下更新,重复上面过程。
void my_adjust_heap(vector<int> &num, int l, int r)
{
int lr = l * 2 + 2;
while (lr < r)
{
if (num[lr] < num[lr - 1])
lr--;
if (num[l] < num[lr])
swap(num[l] , num[lr]);
l = lr;
lr = l * 2 + 2;
if (lr == r)
{
if (num[l] < num[lr-1])
swap(num[l], num[lr-1]);
l = lr - 1;
lr = l * 2 + 2;
}
}
}
void my_make_heap(vector<int> &num,int l,int r)
{
if (r - l < 2) return;
int len = r - l;
int parent = (len - 2) / 2;
while (parent >= 0)
{
my_adjust_heap(num, parent, r);
--parent;
}
}
2:插入一个新元素
把新元素放到数组最后,通过大小,更新最后的节点和它的父节点。
然后顺着路径往上更新,重复上面过程。
void my_push_heap(vector<int> &num, int number)
{
num.push_back(number);
int child = num.size()-1;
int father = (child -1)/ 2 ;
while (father >= 0 && father < child)
{
if (num[father] < num[child])
swap(num[father], num[child]);
child = father;
father = (child-1) / 2 ;
}
}
3:弹出堆顶元素
将栈顶元素用尾节点替换,保证完全二叉树的性质。
然后顺着路径往下更新,重复上面过程。
int my_pop_heap(vector<int> &num)
{
int tmp = num[0];
num[0] = num.back();
num.pop_back();
my_adjust_heap(num, 0, num.size());
return tmp;
}
4:堆排序
每次弹出堆顶元素,保证最大值。
从上往下更新节点,保证新堆的完全二叉树性质。
vector<int> my_heap_sort(vector<int> &num, int l, int r)
{
vector<int> ans;
int n = num.size();
for (int i = 0; i < n; i++)
{
ans.push_back(my_pop_heap(num));
}
return ans;
}
5:最终测试代码
void test_heap()
{
vector<int> a = { 0,1,2,3,4,8,9,3,5 };
my_make_heap(a,0,a.size());
for (auto num : a)
cout << num << ',';
cout << endl;
my_push_heap(a, 10);
for (auto num : a)
cout << num << ',';
cout << endl;
my_pop_heap(a);
for (auto num : a)
cout << num << ',';
cout << endl;
a = my_heap_sort(a, 0, a.size());
for (auto num : a)
cout << num << ',';
cout << endl;
}