堆排序:二叉树。如果按升序排列,保证父节点的值小于等于子节点的值。
堆排序证明:
1.
for i=n/2 downto 1 do
down(i);
I.每次点i向下操作前保证:以点i的子节点为根节点的子树的所有节点满足它的值小于等于其子节点的值(如果有子节点)。
II.每次点i向下操作后保证:以点i为根节点的子树的所有节点满足它的值小于等于其子节点的值(如果有子节点)。
证明:
down(i)操作中,点i的值修改后必满足“其值小于等于其子节点的值(如果有子节点) ”;对于任意交换值的两个数(子节点和父节点),修改后都满足“父节点的值小于等于其子节点的值(如果有子节点) ”;而对于其它未交换顺序的数,本来就满足“它的值小于等于其子节点的值(如果有子节点)”。所以得证。
2.每次取出a[1]的值,把a[n]的值放入a[1](n为当前堆的大小,即树节点的数目),然后对a[1]进行down操作。
证明:
根节点a[1]总可以通过某条路径到达某个点a[s],设中途经过点d1,d2,…,dk,则a[1]<=a[d1]<=a[d2]<=…<=a[dk]<=a[s],所以a[1] 保证是二叉树中的最小值。
然后对a[1]进行down操作,根据I“每次点i向下操作后保证:以点i为根节点的子树的所有节点满足它的值小于等于其子节点的值(如果有子节点)。”,所以对a[1]进行down操作后,保证当前a[1]是当前二叉树中的最小值。得证。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define maxn 10000 4 5 long a[maxn+1],n; 6 7 void down(long i) 8 { 9 long j,temp; 10 while (1) 11 { 12 j=i<<1; 13 if (j>n) 14 break; 15 if (j!=n && a[j]>a[j+1]) 16 j++; 17 if (a[i]>a[j]) 18 { 19 temp=a[i]; 20 a[i]=a[j]; 21 a[j]=temp; 22 } 23 else 24 break; 25 i=j; 26 } 27 } 28 29 int main() 30 { 31 long nn,i; 32 scanf("%ld",&n); 33 for (i=1;i<=n;i++) 34 scanf("%ld",&a[i]); 35 for (i=n >>1;i>=1;i--) 36 down(i); 37 nn=n; 38 for (i=1;i<=nn;i++) 39 { 40 printf("%ld ",a[1]); 41 a[1]=a[n]; 42 n--; 43 down(1); 44 } 45 return 0; 46 }