排序系列--堆排序

来源:互联网 发布:微信js接口安全域名 编辑:程序博客网 时间:2024/06/18 05:34

选择类排序--堆排序

思想:

1.建立大顶堆(小顶堆),此时产生的序列并不是有序的。但是确是局部有序的。因为堆是完全二叉树,且每个结点的值都大于或者等于其左右孩子。a[s]>=a[2*s],a[s]>=a[2*s+1],注意结点关系。--根据完全二叉树得到的性质。

如何建堆呢?从length/2开始到结点1(均不是叶子结点),对每个结点进行调整。从length/2+1到length,均是叶子结点。

2.输出有序序列。(即排序)。对于大顶堆,可知,根节点必然是最大值。可将根节点与最后一个节点呼唤,然后对其余n-1个结点进行重新建堆。如此,便可得到有序序列。

heapSort()方法中有三个循环,第一个是用于生成大顶堆。第二个是从后向前排序。第三个是输出排好序的序列。

#include <iostream>
using namespace std;
#define MAXSIZE 20

void heapAdjust(int a[],int s, int m)
{
    int tmp;
 int j;
 tmp = a[s];   // tmp是当前要调整的结点
 for (j=2*s; j<=m; j=j*2)
 {
     if(j<m && a[j] < a[j+1])  // j<m必须有。因为当j == m时,j+1结点是已经筛选过的。不能再参与比较,不能让j++.
  {
      j++;   //  j是孩子结点中较大的结点
  }
  if (tmp > a[j])
  {
      break;
  }
  a[s] = a[j];
  s=j;  // s是指向当前刚刚移动走的结点
 }
 a[s] = tmp;
}

void heapSort(int a[], int length)
{
    int i;
    int tmp;
     for (i=length/2; i>0; i--) // 从非叶子结点开始调整,通过与孩子比较,找到最大的做父节点。
    {
         heapAdjust(a, i, length);
    }
    for (i=length; i>1; i--)
    {
     tmp = a[i];   //与当前最大值a[1]交换。使1到i-1重新建堆。
     a[i] = a[1];
     a[1] = tmp; 
      heapAdjust(a, 1, i-1); // i--是对所有结点的排序过程。但此处传入参数为 i-1,是从1到当前结点的前一个结点建堆。因为第i个结点已经是换过的。是当前的最大值。
    }
    for (i=1; i<=length; i++)
    {
        cout<<a[i]<<endl;
    }
}


int main()
{
 int arr[MAXSIZE]={0};
    int n;
    int i;
 
 cout<<"输入数据的个数"<<endl;
 cin>>n;
 cout<<"输入数据:"<<endl;
 for(i=1; i<=n; i++)
 {
    cin>> arr[i];
 }
  heapSort(arr, n);

  return 0;
}