为了账号安全,请及时绑定邮箱和手机立即绑定

【编程能力不行?那就写啊!】堆排序详解

标签:
C++ 数据结构
正文之前

最近终于状态恢复,所以兴致很高的来解决下前阵子堆积的一些知识输出问题。本文就专讲堆排序,以前一直是冒泡排序的时代,这次就来个效率更高的,确实堆排序虽然代码比冒泡复杂了五到十倍,但是效率确实是一个量级的提升!美滋滋!

正文

推荐一篇比我的好看很多的博客,当然内容不一定有我的详细哈!我也没看很多:

排序六 堆排序

#include<iostream>
using namespace std;
// define the bigest size of the array 
#define MaxLength 12

// define the heapsize of the heap 
#define Heap_Size 10

// define the swap function to swap two variable's figure
void swap(int &a,int &b)
{
    int tmp=a;
    a=b;
    b=tmp;
}

下面这段是全文的核心,这个函数的内容是把数组想象成一个完美二叉树,然后通过递归迭代,每次在一个父节点和该父节点的所有子节点之间寻找最大值,如果父节点不是最大的,那么就继续往下寻找最大值,当然,这个向下的过程意义不大,因为在构造最大堆的过程中,我们会从最下层的父节点开始,然后层层往上推,直到把最大的数置顶到根节点的位置。

// the kernel function of this way, we use this function tobuild the heap and find the bigest figure of the heap
void MaxHeap(int a[MaxLength],int i,int heapsize)
{
    // 完美二叉树的左子树,右子树分别是当前索引的2倍以及两倍+1
    int left=i<<1;
    int right=left+1;
    // we now suppose the bigest one is the father
    int largest_index=i;
    // two if judgement to find the bigest one in the three 
    if(left<= heapsize && a[left]>a[i])
        largest_index=left;
    if(right<= heapsize && a[right]>a[largest_index])
        largest_index=right;
    //if the father isn't the bigest one, we change swap them,and find if there are any bigger one of the heap
    if(largest_index!=i)
    {
        swap(a[largest_index],a[i]);
        MaxHeap(a,largest_index,heapsize);
    }
}

建堆的过程是艰辛的,当然,我说的是理解,代码就那么两行~
为什么这里是MaxLength/2 呢? 因为我们只需要找出所有的非叶节点,找出最大的那个置顶,可以看成是除了根节点之外,所有的节点都有上司,那么如果下属的实力要比上司强,那么我们就会选出最强的那个人获得最高的职位,那么就要从最小的那个上司开始进行升职仪式,直到最后到了根节点那儿才停下。

void Build_Heap(int a[MaxLength],int heapsize=Heap_Size)
{
    for (int i = MaxLength/2; i>0; --i)
    {
        MaxHeap(a,i,heapsize);
    }
}

为什么这里是MaxLength/2 呢? 因为我们只需要找出所有的非叶节点,找出最大的那个置顶,可以看成是除了根节点之外,所有的节点都有上司,那么如果下属的实力要比上司强,那么我们就会选出最强的那个人获得最高的职位,那么就要从最小的那个上司开始进行升职仪式,直到最后到了根节点那儿才停下。


void Heap_Sort(int a[MaxLength])
{
    int heapsize=Heap_Size;
    // Build_Heap(a);
    for (int i = Heap_Size; i > 1; --i)
    {
        swap(a[1],a[i]);
        //注意此处,一定要减短长度,因为我们已经把最大值放到最后去了。
        --heapsize;
        MaxHeap(a,1,heapsize);
    }
}

下面是指某个位置的值突然增大,那么我们就需要重构最大堆,因为你增大之后可能会导致当前位置的值比当前最大堆的根节点还要大,那最大堆就只是个口号了!

void Increase_Key(int a[MaxLength],int i,int key)
{
    if(a[i]>key)
        cout<<"Error! your input key is smaller than the current key!"<<endl;
    else
    {
        a[i]=key;
        while(i>1 && a[i/2]<a[i])
        {
            swap(a[i/2],a[i]);
            i=i>>1;
        }
    }
}

下面是插入一个新的叶节点,首先可以看到的是,把它放在数组的最后,然后直接视为在最后的位置从0开始增加到当前值,重构最大堆。

void Insert_Key(int a[MaxLength],int key)
{
    a[Heap_Size+1]=-1;
    Increase_Key(a,Heap_Size+1,key);
}

来来来,看看效果!

int main()
{
    int a[MaxLength];
    int length=11;
    while(length--)
    {
        cin>>a[10-length];
    }
    Build_Heap(a);
    for(int s=1;s<MaxLength-1;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    Heap_Sort(a);
    for(int s=1;s<MaxLength-1;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    Increase_Key(a,5,30);
    for(int s=1;s<MaxLength-1;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    Insert_Key(a,17);
    for(int s=1;s<MaxLength;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    return 0;
}

下面是所有的代码汇总,需要的直接copy就能用!

#include<iostream>
using namespace std;
// define the bigest size of the array 
#define MaxLength 12

// define the heapsize of the heap 
#define Heap_Size 10

// define the swap function to swap two variable's figure
void swap(int &a,int &b)
{
    int tmp=a;
    a=b;
    b=tmp;
}

// the kernel function of this way, we use this function tobuild the heap and find the bigest figure of the heap
void MaxHeap(int a[MaxLength],int i,int heapsize)
{
    // 完美二叉树的左子树,右子树分别是当前索引的2倍以及两倍+1
    int left=i<<1;
    int right=left+1;
    // we now suppose the bigest one is the father
    int largest_index=i;
    // two if judgement to find the bigest one in the three 
    if(left<= heapsize && a[left]>a[i])
        largest_index=left;
    if(right<= heapsize && a[right]>a[largest_index])
        largest_index=right;
    //if the father isn't the bigest one, we change swap them,and find if there are any bigger one of the heap
    if(largest_index!=i)
    {
        swap(a[largest_index],a[i]);
        MaxHeap(a,largest_index,heapsize);
    }
}

void Build_Heap(int a[MaxLength],int heapsize=Heap_Size)
{
    // 为什么这里是MaxLength/2 呢? 因为我们只需要找出所有的非叶节点,找出最大的那个置顶
    //可以看成是除了根节点之外,所有的节点都有上司,那么如果下属的实力要比上司强,那么我们就会选出最强的那个人获得最高的职位
    //那么就要从最小的那个上司开始进行升职仪式,直到最后到了根节点那儿才停下。
    for (int i = MaxLength/2; i>0; --i)
    {
        MaxHeap(a,i,heapsize);
    }
}

//堆排序的过程就是,我们每一次堆排序,都会把最大的那个数置顶到根节点,那么我们把现在的这个最大值放到数组的最后
//然后缩短我们堆排序的长度,也就是说把最大值的那个数组索引排除在堆排序之外,然后找到第二大的那个放在前面的那个最大值之前
//然后重复这个过程,就可以获得一个从小到大的排序了
void Heap_Sort(int a[MaxLength])
{
    int heapsize=Heap_Size;
    // Build_Heap(a);
    for (int i = Heap_Size; i > 1; --i)
    {
        swap(a[1],a[i]);
        //注意此处,一定要减短长度,因为我们已经把最大值放到最后去了。
        --heapsize;
        MaxHeap(a,1,heapsize);
    }
}

void Increase_Key(int a[MaxLength],int i,int key)
{
    if(a[i]>key)
        cout<<"Error! your input key is smaller than the current key!"<<endl;
    else
    {
        a[i]=key;
        while(i>1 && a[i/2]<a[i])
        {
            swap(a[i/2],a[i]);
            i=i>>1;
        }
    }
}

void Insert_Key(int a[MaxLength],int key)
{
    a[Heap_Size+1]=-1;
    Increase_Key(a,Heap_Size+1,key);
}

int main()
{
    int a[MaxLength];
    int length=11;
    while(length--)
    {
        cin>>a[10-length];
    }
    Build_Heap(a);
    for(int s=1;s<MaxLength-1;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    Heap_Sort(a);
    for(int s=1;s<MaxLength-1;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    Increase_Key(a,5,30);
    for(int s=1;s<MaxLength-1;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    Insert_Key(a,17);
    for(int s=1;s<MaxLength;++s)
        cout<<a[s]<<" -> ";
    cout<<"done!"<<endl;

    return 0;
}
正文之后

溜溜溜~~ mmp 真是刺激!!

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消