//堆排序是利用堆的特性进行排序的过程
//堆是一个完全二叉树,树中每个结点对应于原始数据的一个记录,并且每个结点应满足以下条件:非叶结点的数据大于或等于其左、右孩子结点的数据,
//当要按从小到大的顺序排序,则要求根结点为最大值。(记住)
//在堆排序算法中,我们使用的是最大堆。最小堆通常在构造优先队列时使用,
/*堆可以被看成是一棵树,结点在堆中的高度定义为从本结点到叶子的最长简单下降路径上边的数目(算法导论中是从0开始的);定义堆的高度为树根的高度
下面来看max_heapify(),保持堆的性质,让a[i]在最大堆中下降,使以i为根的子树成为最大堆*/
void max_heapify(int a[],int i)
{//输入一个数组和下标 使a[i]满足最大堆性质
int l,r,largest,temp;
int heap_size;//存放在A中的堆的元素个数
l=left(i);//i结点的左孩子
r=right(i);//i结点的右孩子
if(l<=heap_size && a[l]>a[i])
largest=l;
else
largest=i;
if(r<=heap_size && a[r]>a[largest])
largest=r;
if(largest!=i)
{
temp=a[i];
a[i]=a[largest];
a[largest]=temp;
max_heapify(a,largest);
}//注意我写的是算法,可能需要修改才能运行一下
}
/*分析这个过程:在算法的每一步里,从元素a[i],a[l],a[r]中找出最大的,并将其下标存在largest中。如果a[i]是最大的,则以i为根的子树已经是最大堆
,程序结束。否则,i的某个结点中有最大元素,则交换a[i]和a[largest],从而使i及其子女满足堆性质。下标为largest的结点在交换后的值是a[i],以该
结点为根的子树又有可能违反最大堆性质。因而要对该子树递归调用max_heapify*/
/*下面我们来建堆:我们可以自底向上地用max_heapify来将一个数组a[1...n]变成一个最大堆
子数组a[(n/2+1)..n]中的元素都是树中的叶子,因此每一个都看作是只含一个元素的堆.注意了,我这里完全二叉树中第一个元素的下标是从1开始*/
void build_max_heap(int a[])
{//看好了,兄弟们
int length;//数组元素的元素个数 或许我这里数组元素中所有元素并不一定都满足完全二叉树吧 所以产生了length与heap_size
int heap_size;//上面解释过了
heap_size=length;
for(i=length/2;i>=1;i--)//仔细看看,最好画个图
max_heapify(a,i);
}
//最后我们来堆排序算法
void build_max_heap(int a[])
{
int i;
for(i=length;i>=2;i--)//length为数组元素的长度,heap_size是存放在a中的堆的元素的个数
{
temp=a[1];
a[1]=a[i];
a[i]=temp;
heap_size--;
max_heapify(a,1);
}
}
/*开始时,堆排序算法先用build_max_heapify()将输入数组a[1...n](此处n=length)构造成一个最大堆。因为数组中最大元素在根a[1],则可以通过把它与a[n]
互换来达到最终正确的位置。现在,如果从堆中“去掉”结点n(通过减小heap_size),可以很容易地将a[1...n-1]建成最大堆。原来根的子女仍是最大堆
而新的根元素可能违背了最大堆性质。这时调用max_heapify(a,1)就可以保持这一性质,在a[1...n-1]中构造出最大堆。堆排序算法不断重复这个过程,堆
的大小由n-1一直降到2
*/