堆排序
分为两类:
1.大顶堆:
父的顶点比孩子结点都大。
2.小顶堆:
父的顶点比孩子结点都小。
举例大顶堆:
1.我们使用的是顺序存储【数组】,按层次存储(从上至下,从左至右),
那么我们的编号的关系是:若父节点下标为key,那么左孩子结点的下标为2key,右孩子则为2key+1。 (因为右孩子在左孩子右一个位置,我们又按照层次顺序存储,所以左孩子+1等于右孩子)。
2.我们拿到的也是一个数组,但是初始状态并不一定满足大根堆【不是大根堆】,所以我们要维护这个数组,对他进行调整。对初始数组的调整的过程叫做,建立大根堆。
当我们build_sort后我们就获得了一个大根堆。【定义在顶部】
类似于:
我们的真正所需要的是一个降序的序列,而现在是看不出来的。
关键操作来了:
当我们通过build_heap 获得了一个大顶堆,【注意当前的长度为length】我们还要对他进行 输出a[1]堆顶元素,然后堆顶元素a[1]和数组的最后一个元素交换。
这时我们认为最后的这个结点(值为4)已经不属于大顶堆。因此长度变为length-1
这个时候我们的大顶堆相当于变成了下图,只有3个顶点,现在已经不满足定义,因为堆顶元素破坏了大顶堆的结构(破坏了定义)。
因此我们只需要把堆顶元素进行调整 adjust_heap
我们就会得到新的大顶堆(也不能说是新的,就是我们需要的结果)
现在是不是又回到了我们刚开始第一步的操作的样子,,这样就可以永远保证堆顶元素是剩下的顶点构成的集合中的最大值。输出堆顶元素a[1]
因此,一个循环直到堆顶元素,我们就会按照降序输出了。
代码如下:
void heap_sort(int length){
//建立大根堆后 才获得一个大根堆 才能用来输出
build_heap();
for(int i=length;i>=1;i--){
//注意这里是输出堆顶元素 a[1] 不要写成 a[i] ,今天写的时候就是因为这个问题搞了好久,最后才发现,吐了。
cout<<a[1]<<" ";
//这里的i就是长度
adjust_sort(a[1],i--);
}
}
4.build_heap:
我们只需要对非叶结点的最后一个有孩子结点的 位置开始 直到 数组存储数据的第一个位置 1 ,对这个区间的元素按倒序进行调整。
上图就是 从值为5的结点开始一直往前 到值为3的结点为止
那个开始的位置是 length/2, 在这里就不推了。
//建立堆的代码
void build_heap(){
for(int i=length/2;i>=1;i--){
adjust_heap(a[i],length);
}
}
5.无论是在建堆的过程中还是,输出的过程中都要调整堆adjust
- 为什么要调整堆,我们建立的是大顶堆,一旦不符合大顶堆的定义就需要调整
- 定义:父结点要比孩子结点都大
- 从定义中可以看出两个东西:
- ①如果有孩子结点(非叶结点),父结点要比孩子结点都大
- ②如果没有孩子结点(叶结点) 则不需要进行操作
思路:
- 传了一个需要调整的结点下标key,我们先保存这个元素的值到a[0]
- 我们通过他与他的孩子们的关系判断他是否符合大顶堆的定义
- 若符合那么不做操作
- 若不符合则 当前key的位置替换成最大的孩子,而key需要移动到那个孩子的位置,因为替换了后,原来的位置已经满足定义,而我们这个key的位置也算是新加进来的。
- 到这个时候也是回到了第一步,所以迭代操作。
迭代的时候采用*2的递增速度,因为每次都是找其孩子。
代码:
void adjust_heap(int key, int length){
a[0]=a[key];
for(int i=key*2;i<=length;i*=2){
if(i<length && a[i+1]>a[i]) i++;
if(a[0]>a[i]){
break;
}else{
a[key]=a[i];
key=i;
}
}
a[key]=a[0];
}
最后附上完整源代码:
其他排序源码传送门
#include <iostream>
using namespace std;
int a[11] = {0,14,9,6,13,21,10,16,17,2,12};
void swap(int *a,int *b) {
int *t = a;
a = b;
b =t;
}
void adjustDown(int key, int length) {
a[0]= a[key];
int j;
for (j =key*2; j <=length; j*=2)
{
if (j<length && a[j]<a[j+1]) {
j++;
}
if (a[0] >=a[j]) {
break;
}
else {
a[key] = a[j];
key = j;
}
}
a[key] = a[0];
}
void my_build_heap(int length) {
for (int i = length/2; i >0; i--)
{
adjustDown(i,length);
}
}
void my_heap_sort(int length) {
my_build_heap(length);
for (int i =length; i>0; i--)
{
cout << a[1] << " ";
swap(a[1], a[i]);
adjustDown(1,i-1);
}
}
int main()
{
my_heap_sort(10);
return 0;
}