堆排序

堆排序:

1.堆排序视为一颗完全二叉树,初始序号按层序赋予,从1开始。

2.与快排时间复杂度相同logn,常数空间复杂度

3.不稳定

4.对于有序,无序的序列效率区别不大。

堆排序的核心操作:

  • 建堆

    BuildMaxHeap();

    从[n/2]到根节点1,循环根据当前节点为调整子树。

  • 调整

    HeapAdjust();

    调整以k序号为根的子树

  • 排序(依次输出堆顶到指定位置,从尾部倒放入原数组)

    HeapSort();

维护操作:

  • 插入

    HeapIns();

    数组末尾加上此元素,然后重新build整个树(也就是从新结点的父亲开始不断向上调整)

  • 删除

    HeapDel();

    输出堆顶==删除

    堆顶和堆底元素swap,然后进行堆调整,范围减少,调整端下标为1的一端固定,右边缩移。

注意: 顺序储存数组空间a[N], 其中 a[0] 作辅助量不参与排序。大根堆排序后,是倒序的从大到小。

区分build 和 Adjust 操作,build会自下而上完全检查变动树的堆特性,执行完就代表树结构已经正确了,sort只是输出使用,而Adjust是检查子树堆特性。

#include<stdc++.h>
using namespace std;

void BuildMaxHeap(int a[],int len);
void HeapAdjust(int a[],int k,int len);
void HeapSort(int a[],int len);

//从最大序号的非终端结点开始自下至上进行调整,建堆
void BuildMaxHeap(int a[],int len){
    for(int i=len/2;i>0;i--)
        HeapAdjust(a,i,len);
}

//调整以k为根的子树
void HeadAdjust(int a[],int k,int len){
    a[0]=a[k];
    for(int i=2*k;i<=len;i*=2){
        if(i<len && a[i]<a[i+1])
            i++;
        if(a[0]>=a[i]) break;
        else{
            a[k]=a[i];   //这里不是交换,大元素上移,小元素待定放在a[0],减少交换次数
            k=i;
        }
    }
    a[k]=a[0];  //将小元素下坠到指定位置
}

//堆排序
void HeapSort(int a[],int len){
    BuildMaxHeap(a,len);
    for(int i=len;i>1;i--){
        swap(a[1],a[i]);
        HeapAdjust(a,1,i-1);
    }
}
int main()
{
    int a[]={0,1,13,2,44,93}; //a[0] 仅作辅助空间,不是堆元素
    
    //验证将一个顺序存储的完全二叉树转换成大根堆
    HeapAdjust(a,1,5);    
    for(int i=1;i<=5;i++)
        cout<<a[i]<<" ";
    puts("");

    //验证堆排序
    HeapSort(a,5);  
    for(int i=1;i<=5;i++){
        cout<<a[i]<<" ";
    }
    return 0;
}
output:
13 93 2 44 1
1 2 13 44 93
posted @ 2022-06-08 20:17  秋月桐  阅读(67)  评论(0编辑  收藏  举报