选择排序------堆排序

堆排序快速排序归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。

堆排序有点类似选择排序,都是每次选出最大的数或最小的数。

对于堆,由于其根节点为堆中最大的节点,因此每次只需取出其根节点,然后重新建堆,再重复前面操作

故按如下步骤:

  首先可以看到堆建好之后堆中第0个数据是堆中最大的数据。取出这个数据再执行下堆的删除操作。这样堆中第0个数据又是堆中最大的数据,重复上述步骤直至堆中只有一个数据时就直接取出这个数据。

  由于堆也是用数组模拟的,故堆化数组后,第一次将A[0]与A[n - 1]交换,再对A[0…n-2]重新恢复堆。第二次将A[0]与A[n – 2]交换,再对A[0…n - 3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最小的数据并入到后面的有序区间,故操作完成后整个数组就有序了。

     在前面介绍了对的删除,插入和建堆等操作(加了哨兵,数组从第1个元素开始),下面实现堆排序。

 

#include <iostream>

using namespace std;

struct  Heap_Struct{
     int *Element;
     int size;
     int capacity;
};

void Heap_Sort(void); 
Heap_Struct*  Heap_Construct(int *arr,int len);
int Heap_Delete(Heap_Struct *h);

int main()
{
    Heap_Sort( );
    return 0;
}

Heap_Struct*  Heap_Construct(int *arr,int len)
{/*根据长度为len的数组创建最大堆*/
    
      Heap_Struct  *H_tmp= new Heap_Struct;
      H_tmp->Element=new int[len+1];
      H_tmp->size=len;
      H_tmp->capacity=len;

      int i,start,tmp=0;
      int parent,child;
      for (i=1;i<len+1;i++)
        {
            H_tmp->Element[i]=arr[i-1];
            if(tmp<arr[i])
                tmp=arr[i];
        }
      H_tmp->Element[0]=tmp+5;  
      start=i/2;
      for(i=start;i>0;i--)
      {
           parent=i;
            while(2*parent<=H_tmp->size)  //存在子节点 
         {
            if(2*parent+1<=len && H_tmp->Element[2*parent+1]>H_tmp->Element[2*parent] && H_tmp->Element[2*parent+1]>H_tmp->Element[parent])
            {
                   tmp=H_tmp->Element[parent];
                   H_tmp->Element[parent]=H_tmp->Element[2*parent+1];
                   H_tmp->Element[2*parent+1]=tmp;      
                   parent=2*parent+1;
            }
           else if(H_tmp->Element[2*parent]>H_tmp->Element[parent])
            {
                    tmp=H_tmp->Element[parent];
                    H_tmp->Element[parent]=H_tmp->Element[2*parent];
                    H_tmp->Element[2*parent]=tmp; 
                    parent=2*parent;      
            }
           else 
               break;
         }
      }
       return H_tmp;
}        

int Heap_Delete(Heap_Struct *h)
{
     int MaxData=h->Element[1];
     int tmp=h->Element[h->size--];/*取出最后一个元素并将堆的长度减1*/
     int i=1;
     while(2*i<=h->size && h->Element[2*i]>tmp)
     {
            if((2*i+1)<=h->size && h->Element[2*i+1]>h->Element[2*i] && h->Element[2*i+1]>tmp)  /*右节点存在且大于左节点且大于插入的值,则将右节点移到其父节点并继续向上过滤*/
           { 
                    h->Element[i]=h->Element[2*i+1];;
                    i=2*i+1;
           }
            else if(h->Element[2*i]>tmp)   /*左节点大且大于插入的值,则将左节点移到其父节点并继续向上过滤*/
           {
                   h->Element[i]=h->Element[2*i];
                   i=2*i;
            }
            else
                   break;
     }

        h->Element[i]=tmp;   /*将最后一个数插到堆中*/
      return MaxData;
}                      

void Heap_Sort(void)
{
    int arr[]={79,66,43,83,30,87,38,55,91,72,49,9};
    int len=12;
    cout <<"原始数据:"; 
    for(int i=0;i<len;i++)
        cout << arr[i] <<' ';
    cout << endl;
    
    Heap_Struct* h=Heap_Construct(arr,len); //建堆
    
    cout <<"堆中数据:";
    for(int i=1;i<len+1;i++)
        cout << h->Element[i] << ' ';
    cout <<endl;
    
    for(int i=0;i<len;i++)                 //循环删除堆的根节点,并将其插入到数组的末尾 
        arr[len-i-1]=Heap_Delete(h);
    
    cout <<"排序后数据:" ;
    for(int i=0;i<12;i++)
        cout << arr[i] <<' ';
    cout <<endl;
}

结果为:

  

  由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。STL也实现了堆的相关函数,可以参阅《STL系列之四 heap 堆》。

 

posted @ 2016-11-16 23:24  wj_hubei  阅读(267)  评论(0编辑  收藏  举报