手写快速排序:https://blog.csdn.net/weixin_42887343/article/details/119614233
1 堆排序原理
我们一般提到堆排序里的堆指的是二叉堆(binary heap)而不是堆栈的堆,二叉堆是一种完全二叉树,分为最大堆和最小堆(大根堆和小根堆),特点是父节点的值大于(小于)两个小节点的值。
2 快速排序函数
2.1 标准库
#include <algorithm>
标准库算法库中的堆相关函数
- make_heap()用于把一个可迭代容器变成一个堆,默认是大顶堆。
- sort_heap()是将堆进行排序,排序后,序列将失去堆的特性(子节点的键值总是小于或大于它的父节点)。
make_heap(v.begin(),v.end());
sort_heap(v.begin(),v.end());
make_heap 是按照给定的排序准则,把“最大”的元素排列到首位,而其他元素看上去并非有序:比如对序列 3 4 5 6 7 5 6 7 8 9 1 2 3 4
,用make_heap 排序后为:9 8 6 7 7 5 5 3 6 4 1 2 3 4
如果你把这些元素转换为二叉树结构,就可以看出来每个节点的值都小于或等于其父节点值,此外heap 算法能够保证在对数时间内增加或移除一个元素,是实做优先队列的理想结构。
2.2 手写函数
void Heap_build(int data[],int root,int length)
{
int lchild = root*2+1; //根节点的左子结点下标
if (lchild < length) //左子结点下标不能超出数组的长度
{
int flag = lchild; //flag保存左右节点中最大值的下标
int rchild = lchild+1; //根节点的右子结点下标
if (rchild < length) //右子结点下标不能超出数组的长度(如果有的话)
if (data[rchild] > data[flag]) //找出左右子结点中的最大值
flag = rchild;
if (data[root] < data[flag])
{
std::swap(data[root],data[flag]); //交换父结点和比父结点大的最大子节点
Heap_build(data,flag,length); //从此次最大子节点的那个位置开始递归建堆
}
}
}
void Heap_sort(int data[],int len)
{
for (int i = len/2; i >= 0; --i)//从最后一个非叶子节点的父结点开始建堆
Heap_build(data,i,len);
for (int j = len-1; j > 0; --j)//j表示数组此时的长度,因为len长度已经建过了,从len-1开始
{
std::swap(data[0],data[j]);//交换首尾元素,将最大值交换到数组的最后位置保存
Heap_build(data,0,j);//去除最后位置的元素重新建堆,此处j表示数组的长度,最后一个位置下标变为len-2
}
}
3 demo代码
3.1 使用标准库函数
int main(int argc, char *argv[])
{
vector<int> v; //将myints复制到v
for(int i=0;i<1000;i++) //随机生成10个数并排序
v.push_back(rand()%1000);
cout << "\n init: \n";
for (int i = 0;i < v.size();i ++) cout << ' ' << v[i];
make_heap(v.begin(),v.end());
sort_heap(v.begin(),v.end());
cout << "\n\n out: \n";
for (int i = 0;i < v.size();i ++) cout << ' ' << v[i];
return 0;
}
3.2 使用手写函数
int main(int argc, char *argv[])
{
int arr[] = { 49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22 };
Heap_sort(arr, 13);
for(int i = 0;i < 13;i ++)
qDebug()<<arr[i];
return 0;
}