当前位置:   article > 正文

大小堆排序 & Top K 问题_topk

topk

大小堆排序

堆这种数据结构定义比较简单,大根堆就是父节点的值大于左右子孩子节点的值(小根堆相反),而且利用数组下标就可以很好的表现堆(不过要注意是从0 还是 1开始)。堆常用语实现优先队列,Top K等问题。

算法导论第6章对堆的进行了详细讲解,我就不赘述了(看书是不够的,要把思路用代码实现出来才是真的懂了,争取把算法导论上常用的数据结构和算法都自己实现一般)。

大根堆

具体代码(按照算法导论中下标从1开始):

/******* 大小堆排序 & topk问题  ***********/

//调整大根堆(大堆化),数组从1下标开始
void adjust_maxheap(int a[],int size,int i)
{

    int left = i*2; //左节点
    int right = i*2+1; //右节点
    int max_index;

    //找根,左,右中最大的节点
    if(left < size && a[left]>a[i])
        max_index = left;
    else
        max_index = i;

    if(right < size && a[right] > a[max_index])
        max_index = right;

    //如果原来的根不是最大值,则需要交换,交换后原来max值的节点变成了比较小的根
    if( i != max_index ) 
    {
        SWAP(a[i],a[max_index]);
        adjust_maxheap(a,size,max_index);
    }
}


//建立大根堆
void build_maxheap(int a[],int size)
{
    int start = size>>1; //第一个非叶子节点
    int i ;
    for(i = start;i>=1;i--)
    {
        adjust_maxheap(a,size,i);
    }
}

//大堆排序
void maxheap_sort(int a[],int size)
{
    int i;
    for(i = size;i>=1;i--)
    {
        build_maxheap(a,i);
        SWAP(a[1],a[i]);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

测试代码与运行截图:

这里写图片描述

小根堆

具体代码(下标从0开始):

void adjust_minheap(int a[],int size,int i)
{
    int left = i*2+1;
    int right = i*2+2;

    int min_index;
    if( left < size && a[left]<a[i])
        min_index = left;
    else
        min_index = i;

    if( right < size && a[right]< a[min_index])
        min_index = right;

    if( min_index != i)
    {
        SWAP(a[i],a[min_index]);
        adjust_minheap(a,size,min_index);
    }
}

void build_minheap(int a[],int size)
{
    int start = size>>1;
    for(start;start>=0;start--)
    {
        adjust_minheap(a,size,start);
    }
}

void minheap_sort(int a[],int size)
{
    int i,j=size,last= size -1;
    for(i = 0;i<size;i++)
    {
        build_minheap(a,j--);
        SWAP(a[0],a[last]);
        last -= 1;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

测试代码与运行截图:

这里写图片描述

运用堆排序解决Top K问题

top k问题就是在一堆数据中选择前K大(前K小)的数据。做法有许多,可以先把所有数据排序,然后选前k个。
然后用堆排序解决Top K问题则不用先全部排序,只需维护一个大小为K的堆即可。

实现思路:

如果要选出前K大,则将数据中的前K个元素建立成一个小根堆,从第K+1个元素开始往后依次比较,如果元素大于小根堆的堆顶,那么就和堆顶交换,交换后重新调整为小根堆。这样变量一遍所有数据,最后得到的大小为K的小根堆就是前K大的树。

具体代码:

void topk_biggest(int a[],int size,int k)
{
    int i;

    for(i = k;i<size;i++)
    {
        build_minheap(a,k);
        if(a[i]>a[0])
            SWAP(a[i],a[0]);
    }
    printf("最大%d个数为:",k);
    for(i =0;i<k;i++)
        printf("%d ",a[i]);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Top k 测试代码&运行截图:

这里写图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/716792
推荐阅读
相关标签
  

闽ICP备14008679号