一、基础概念
1.二叉树
二叉树是每个节点最多有两个子节点的树结构;特点是①每个节点最多有两个字节;②二叉树的子树有左右之分。
2.堆
①是一个完全二叉树
②所有父节点的值大于(或者小于子节点的值)
③每个节点的值都大于其子节点的堆成为大顶堆;
每个节点的值都小于其子节点的堆称为小顶堆。
3.关系
①该节点(i)的父节是 (i-1)/2
②该节点的左孩子是i2+1;
③该节点的右孩子是i2+2;
二、基本思想
先把数组构造成一个大顶堆,然后把堆顶的元素和最后一个元素交换,这样最大值就到了最后面。
我们需要做的就是
①先把一堆无序的数构造成大顶堆——建堆
②排序,使得数组的值由小到大——排序
三、思路
1.建堆
给一组数据 int a[len]={6,90,200,103,7,1};
二叉树是
显然他还不是堆。所以我们通过堆的性质建堆。
先看代码:
void AdjustHeap(int *a, int i, int len)
int temp = a[i];
for(int child; 2*i+1 < len; i = child)
child = 2*i+1;
if(child != len-1 && a[child] < a[child+1])
++child;
if(temp < a[child])
a[i] = a[child];
else
break;
}
a[i] = temp;
}
形参是要传递这个无序的数组,以及数组长度和开始的位置(i)。
回到上面的二叉树, 我们要从最后一个有子节点的节点开始,可以看到下标为2,即为len/2-1;
所以i=len/2-1;他的左孩子就是child=2*i+1;
if(child != len-1 && a[child] < a[child+1])
++child;
如果左孩子为数组最后一个,那么直接比较左孩子和父节点的大小;如果不是数组最后一个,那么先和右孩子比较。大的那个再和父节点比较。这一小部分就完成,i-1转移到另一个小部分,再比较。
2.排序
当大顶堆建好后,就要让这个数组变得有序。我们就把堆顶的数据和最小的那个比较。最大的值就到了最后,如此循环就排好序。
先看代码:
void HeapSort(int *a, int len)
{
int i;
for(i = len/2; i >= 0; --i)
{
AdjustHeap(a, i, len);
}
//上边是建大顶堆
for(i = len-1; i > 0; --i)
{
Swap(&a[0], &a[i]);
AdjustHeap(a, 0, i);
}
}
swap函数用来交换首位的元素。当最大值到了最后。那么剩余的元素再一次建大顶堆。之后再将新的堆顶放最后。
完整代码:
#include <stdio.h>
void Swap(int * a, int * b);
void HeapSort(int *a, int len);
void AdjustHeap(int *a, int i, int len);
int main(void)
{
int len,i;
len=6;
int a[len]={6,90,200,103,7,1};
HeapSort(a, len); //调用排序函数
for(i = 0; i < len; ++i)
{
printf("%d ", a[i]);
}
printf("\n"); //输出排序结果
return 0;
}
void HeapSort(int *a, int len)
{
int i;
for(i = len/2; i >= 0; --i)
{
AdjustHeap(a, i, len);
}
for(i = len-1; i > 0; --i)
{
Swap(&a[0], &a[i]);
AdjustHeap(a, 0, i);
}
}
void AdjustHeap(int *a, int i, int len) //调整成大顶堆
{
int temp = a[i];
for(int child; 2*i+1 < len; i = child) //当没有孩子时跳出循环
{
child = 2*i+1;
if(child != len-1 && a[child] < a[child+1])
++child;
if(temp < a[child])
a[i] = a[child]; //采用大顶堆,比孩子节点小,则交换
else
break;
}
a[i] = temp;
}
void Swap(int * a, int * b) //交换元素
{
int t;
t = *a;
*a = *b;
*b = t;
}