n个元素求m个最大的元素

本文介绍了一种使用小顶堆高效找出数组中最大的m个数的方法。通过维护一个大小固定的小顶堆来逐步筛选出目标元素,避免了对全部元素进行排序带来的额外开销。

n个元素求m个最大的元素:小顶堆的方法

1. 思路:先只建立一个含有m个元素的小顶堆;然后,利用小顶堆,对其它(n-m)个元素依次判断;最后得到一个m个最大元素的堆。

程序:

#include <iostream>
using namespace std;

void exchange(int &a,int &b)   
{   
    int t=a;   
    a=b;   
    b=t;   
}   

int parent(int i)   
{   
    return i>>1;   
}   
 
int left(int i)   
{   
   return i<<1;   
}   
 
int rigth(int i)   
{   
    return (i<<1)+1;   
}   
 
void min_heapify(int heapsize,int i, int a[])   
{   
   int le=left(i);   
    int ri=rigth(i);   
    int minimum; 
    
    if (le<=heapsize && a[le]<a[i])   
        minimum = le;   
    else  
        minimum = i;   
    
    if (ri<=heapsize && a[ri]<a[minimum])   
        minimum = ri;   
   
    if (minimum!=i)   
    {   
       exchange(a[i],a[minimum]);   
       min_heapify(heapsize, minimum, a);   
    }   
}  
 
void build_min_heap(int m, int a[])   
{   
   int i;   
    
   for (i=m/2;i>=1;i--)   
        min_heapify(m, i, a);  
}   
 
void heapsort(int a[], int n, int m){   
    build_min_heap(m, a);     
    
    for (int i=m+1;i<=n;i++) {
        
        if(a[i]> a[1]) {
           
            exchange(a[i], a[1]);
            build_min_heap(m, a);  
                                
        }       
    }      
}
  
int main(int argc, char** argv) {
    int n=20;//20 nubmers:
    int m=8;//8 largest nubmers:
    
    int a[n+1]; 
      
    for (int i=1;i<=n;i++)   
           a[i] = rand()%99;    
    
    cout<<"n nubmers:"<<endl; 
    for (int i=1;i<=n;i++)   
        cout<<a[i]<<" ";   
    cout<<endl;
    
     heapsort(a, n, m);      

    cout<<"m bigger nubmers:"<<endl;
    for (int i=1;i<=m;i++)   
        cout<<a[i]<<" ";   
    cout<<endl;   
    return 0;
}

程序中m=20, n=8时,输出为:

n nubmers:
65 54 29 86 84 69 34 75 8 46 27 50 57 92 51 95 93 75 83 8
m bigger nubmers:
75 83 75 86 84 93 95 92

 

2. 下面的程序是网上的一种错误做法,其思路是对所有的元素进行大顶堆排序,并依次取出m个最大元素。

#include <iostream>
#define MAXLENGTH 10001
using namespace std;

int a[MAXLENGTH];
int heapsize;
int m;

void exchange(int &a,int &b)   {   
    int t=a;       a=b;       b=t;   
}   

int parent(int i)   {   
    return i>>1;   
}   
 
int left(int i)   {   
   return i<<1;   
}   
 
int rigth(int i)   {   
    return (i<<1)+1;   
}   
 
void max_heapify(int i)   {   
   int le=left(i);   
    int ri=rigth(i);   
    int largest; 
    
    if (le<=heapsize && a[le]>a[i])   
        largest = le;   
    else  
       largest = i;   
    
    if (ri<=heapsize && a[ri]>a[largest])   
        largest = ri;   
   
    if (largest!=i)   
    {   
       exchange(a[i],a[largest]);   
       max_heapify(largest);   
    }   
}   
 
void build_max_heap(int n)   
{   
   int i;   
    heapsize=n;   
   for (i=n/2;i>=1;i--)   
        max_heapify(i);   
}   
 
void heapsort(int n)   
{   
    int i;   
    build_max_heap(n);   
    
    cout<<a[1];  //大顶堆  第一个元素
    
    m--;   
    for (i=n;i>=1;i--)   
    {       
       if (m==0)   
            break;   
       cout<<" ";  
       exchange(a[1],a[i]);   
       heapsize--;   
        max_heapify(1);   
      cout<<a[1];   
       m--;   
   }   
}   
  
int main(int argc, char** argv) {
        int i,n;   
        cin>>n>>m;  
     
        for (i=1;i<=n;i++)   
             a[i]=rand()%99;  
        cout<<"n elements:"<<endl; 
        for (i=1;i<=n;i++)   
           cout<<a[i]<<" ";   
        cout<<endl;   
        cout<<"m largest elements:"<<endl;  
        heapsort(n);   
    return 0;
}

输入:

20 8
输出:

n elements:
65 54 29 86 84 69 34 75 8 46 27 50 57 92 51 95 93 75 83 8
m largest elements:
95 93 92 86 84 83 75 75

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值