堆排序

堆排序用到的是完全二叉树的性质,所以在看这篇文章之前先学习完全二叉树。


 

http://baike.baidu.com/link?url=HUZLyRNtNhAUzf7rgffW3IHkPbNQF_0vO63EvTKZBgYztrMz02B2_-PlCV5eFg6J8y8w8sHEu4Bd7bZVOXozaK


 

 

那么,学会了完全二叉树,现在就可以学习堆排序了。

个人认为,堆排序是插入排序和快排思想的联合,所以读者可以先学会插入排序和快排。

  插入排序:每次选出带排序序列的最大值,加入已排好序的序列;

  快排:在待排序序列中选择一个记录,让它左边的都比它小,右边的都比它大,如此递归。

思考:

  对于插入排序,时间复杂度主要在选择最大值的过程中。有没有一种方法可以用更少的时间就选出最大值呢?

  对于快速排序,如果用完全二叉树存储,让根节点比左子树大,比右子树也大,那这个根节点不就是最大值吗?

两相结合,堆排序应运而生,而核心就是完全二叉树的性质。下面可以看看堆排序相关的概念,有助于理解。


http://baike.baidu.com/link?url=Fc3__n67naxdKu_l7MzWi6WCn4QbbJESFSKiJUvvO-CzszGyoqv0coneADUg6DjcJEAVpymvhqwm8qRe9gEYSK


 

下面是堆排序的代码:

 1 #include<stdio.h>
 2 void creatheap(int *a,int n,int i)  //整理堆的函数,包括三个参数,数组首地址,数组元素个数,要处理的结点编号 
 3 {
 4  if (i*2+1>n)   //如果 这个结点没有右孩子 
 5  {
 6   if (i*2>n) return;  //如果再没有左孩子,直接return 
 7   else    //如果有左孩子,就比较这个结点和左孩子是否需要交换 
 8   {
 9    if (a[i*2]>a[i])
10    {
11     a[0]=a[i];
12     a[i]=a[i*2];
13     a[i*2]=a[0];
14     creatheap(a,n,2*i);  //递归左孩子 
15    }
16    else return;  //不需要交换的话直接return 
17   }
18  }
19  else //如果有右孩子(那么肯定有左孩子啦~) 
20  {
21   if (a[i*2+1]<=a[i]&&a[i*2]<=a[i]) return; //经过比较左右孩子都不需要交换,说明这个堆不用处理了,return 
22   else{  //否则,这个堆需要处理 
23    int maxi=i*2;  //下面分析需要处理左孩子还是右孩子 
24    if (a[i*2+1]>a[i*2]) maxi++;
25    a[0]=a[i];
26    a[i]=a[maxi];
27    a[maxi]=a[0];
28    creatheap(a,n,maxi);  //递归需要处理的那个 
29   }
30  }  //这样就完成了一次整理 
31 }
32 int main()
33 {
34  int b[101]={0};
35  int n;
36  scanf("%d",&n);
37  int i;
38  for (i=1;i<=n;i++)
39  {
40   scanf("%d",b+i);
41  }
42  for (i=n/2;i>=1;i--)  //对非叶子结点递减整理,n/2是第一个非叶子结点的编号 
43  {
44   creatheap(b,n,i);
45  }
46  //这样整理完之后目前这个数组是一个堆了 可以确定的是第一个元素b[1]一定是最值 
47  int k=n;
48  while (n!=1)
49  {
50   b[0]=b[1];
51   b[1]=b[n];
52   b[n]=b[0];
53   n--;
54   creatheap(b,n,1);  //把b[1]移到末尾,然后同理整理前n-1个元素,直到n=1 
55  }
56  for (i=1;i<=k;i++)  //堆排序完成 
57  {
58   printf("%d ",b[i]);
59  }
60  return 0;
61 }

 

posted @ 2015-08-22 14:05  lvmememe  阅读(328)  评论(2编辑  收藏  举报