堆排序

来源:互联网 发布:2020年中国 知乎 编辑:程序博客网 时间:2024/06/10 05:20

/*
n个元素的序列{k1,k2,k3,...kn}称之为堆,当且仅当满足一下条件时:
          1.ki >= k2i 且 ki >= k2i+1 (大根堆)
          2.ki <= k2i 且 ki <= k2i+1 (小根堆)
堆排序算法:
1.按堆的定义将待排序序列L[1...n]调整为大根堆(这个过程称之为初建堆),交换L[1]和L[n],此时L[n]为关键字最大的纪录
2.将L[1...n-1]重新调整为大根堆,交换L[1] 和L[n-1],则L[n-1]为关键字次大的纪录
3.循环n-1次,直到交换了L[1]和L[2],得到一个非递减的有序序列L[1....n]
同样也可以构造小根堆
从以上可以看出堆排序需要解决两个问题:
1.初建堆:如何将一个无序序列建成一个堆
2.调整堆:堆顶元素改变之后,如何调整剩余的元素成为一个新的堆

调整堆的思想:
从L[2s] 和 L[2s+1]中选取较大者,假设L[2s]的关键字较大,比较L[s]和L[2s]的关键字
1.若L[s] > L[2s],说明以L[s]为根的子树已经是堆,不做任何调整
2.若L[s] < L[2s],交换L[s]和L[si].交换后,以L[2s+1]为根的子树是堆,但此时以L[2s]为根
  的子树不一定是堆,则重复上述过程,将以L[2s]为根的子树调整为堆,直到进行到叶子节点为止
初建堆的思想:
对于无序序列L[1..n],从i = 2/n开始,反复调用调整堆,HeapAdjust(L,i,n),一次将L[i],L[i-1],L[i-2]...L[2],L[1]调整为堆

  时间复杂度为 nlog2n

*/

#include <iostream>#include <math.h>#define MAXSIZE 21using namespace std;void HeapAdjust(int Arry[],int s,int last){      int x = Arry[s];      for(int i = 2*s; i <= last; i = i*2)                     {  //          (s)          //         /      \      //         (i)    (i+1)       //        / \      /  \        //      () ()   ()  ()      if(i < last && Arry[i] < Arry[i+1])                      i = i + 1;                                 if(x >= Arry[i])                                    break;      Arry[s] = Arry[i];      s = i;      }      Arry[s] = x;}void CreateHeap(int Arry[],int len){      for(int i = len/2; i > 0; i--)      {                HeapAdjust(Arry,i,len);     //初建堆用的heaoadjust的停止判断条件是s <= len     }}void HeapSort(int Arry[],int len){         CreateHeap(Arry,len);            //初建堆         for(int i = len; i > 1; i--)     //循环n-1次         {                swap(Arry[1],Arry[i]);       //交换Arry[1]和Arry[i]               HeapAdjust(Arry,1,i-1);      //此时Arry[i]存放此次的最大关键值,然后再把1..i-1调整为堆         }}int main(){         int Arry[MAXSIZE] = {0,45,8,94,100,26,45,3,0,15,35,85,67,76,40,19,20,33,200,77,11};        HeapSort(Arry,MAXSIZE-1);        for(int i = 1; i < MAXSIZE; i++)       cout<<Arry[i]<<" ";       cout<<endl;       return 0;}


原创粉丝点击