堆排序、选择排序

堆排序其实也是一种选择排序,是一种树形选择排序

只不过直接选择排序中,为了从R[1...n]中选择最大记录,需比较n-1次

然后从R[1...n-2]中选择最大记录需比较n-2次......

事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过

而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。

对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为nlogn。

堆排序为时间复杂读度不稳定排序,不适合记录较少的排序。

 

建堆以及堆排序的完整代码如下:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int h[101];//用来存放堆的数组
int n;//用来存储堆中元素的个数,也就是堆的大小
//向下调整函数,建立小顶堆 
void siftdown(int i) //传入一个需要向下调整的结点编号i,这里传入1,即从堆的顶点开始向下调整
{
    int t,flag=0;//flag用来标记是否需要继续向下调整
    //当i结点有儿子的时候(其实是至少有左儿子的情况下)并且有需要继续调整的时候循环窒执行
    while(i*2<=n&&flag==0)
    {        
        //首先判断他和他左儿子的关系,并用t记录值较小的结点编号
        if(h[i]>h[i*2])t=i*2;         
        else t=i;          
        //如果他有右儿子的情况下,再对右儿子进行讨论
        if(i*2+1<= n)  
            if(h[t] >h[i*2+1])//如果右儿子的值更小,更新较小的结点编号
                t=i*2+1;    
        //如果发现最小的结点编号不是自己,说明子结点中有比父结点更小的  
        if(t!=i){
            swap(h[t],h[i]);//交换它们
            i=t;//更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整
        }
        else flag=1;//则否说明当前的父结点已经比两个子结点都要小了,不需要在进行调整了
    }
}
//建立堆的函数
void creat(){
    int i;
    //从最后一个非叶结点到第1个结点依次进行向上调整
    for(i=n/2;i>=1;i--)siftdown(i);        
}
//删除最小的元素,并输出 
int deletemax(){
    int t;
    t=h[1];//用一个临时变量记录堆顶点的值
    h[1]=h[n];//将堆得最后一个点赋值到堆顶
    n--;//堆的元素减少1
    siftdown(1);//向下调整
    return t;//返回之前记录的堆顶点,数组的最小值
}
int main()
{
    int i,num;
    scanf("%d",&num);//读入数的个数
    for(i=1;i<=num;i++)scanf("%d",&h[i]);    
    n=num;   
    //建堆
    creat();
    //删除顶部元素,连续删除n次,其实夜就是从小到大把数输出来
    for(i=1;i<=num;i++)printf("%d ",deletemax());
    return 0;
}

 

发布了183 篇原创文章 · 获赞 31 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/mlm5678/article/details/103117767