堆排序

       堆排序是对简单选择排序的一种改进。堆排序可以做到每次在选择到最记录的同时,并根据比较结果对其他记录做出相应的调整,使得排序的总体效率非常高。而简单选择排序的每次比较都没保存下来。

将待排序的序列的每个元素从1开始编号到N,将这些编号了的元素按层次遍历的方式组织成一个完全二叉树,例如一个序列是{50, 10, 90, 30, 70, 40, 80, 60, 20}构成的完全二叉树为:

 

这颗树的大顶堆是:

 

大顶堆的根结点是序列的最大值,每个双亲结点都大于等于它的孩子结点

这颗树的小顶堆:

 

小顶堆的根结点是序列的最小值,每个双亲结点都小于等于它的孩子结点

 

       堆排序算法:(利用大顶堆)将整个待排的序列构造成一个大顶堆,此时整个序列的最大值就是顶堆的根结点。将它移走(与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个大顶堆,这样就得到n个元素的中的次小值。反复执行,直到最后一个元素,编得到了一个有序序列。

 

将第一个元素90和最后一个元素20交换

 

 

重新构造的大顶堆,第一个元素80是最大元素,将它与倒数第二个元素30交换,这样递推下去。。。。。

 

代码:

#include <stdio.h>


void println( int a[], int len )
{
	int i = 0;

	for( i=0; i < len; i++ )
	{
		printf("%d ", a[i]);
	}

	printf("\n");
}

void swap( int a[], int i, int j )
{
	int temp = a[i];

	a[i] = a[j];
	a[j] = temp;
}

/**************
调整完全二叉树,使其满足a[s.....len]
**************/
void HeapAdjust(int a[], int s, int size)
{
	int temp, j;

	temp = a[s];

	/*
	s的左孩子是2*s,右孩子是2*s+1(如果存在的话)
	*/
	for(j = 2*s; j <= size; j *= 2)
	{
		/*判断s的左孩子和右孩子的大小,选择较大的孩子*/
		if( (j < size) && (a[j] < a[j+1]) )
		{
			++j; //指向了右孩子
		}

		/*如果当前根结点比它的孩子大,则不用替换*/
		if(temp >= a[j])
		{
			break;
		}

		/*当前结点比它的孩子小,则替换成它的孩子*/
		a[s] = a[j];
		s = j;   //将孩子结点的位置赋值给s继续循环判断
	}

	a[s] = temp;
}

void HeapSort(int a[], int size)
{
	int i = 0;

	/* 将待排序列构建成一个大顶推 */
	for(i=(size)/2; i > 0; i--)
	{
		HeapAdjust(a, i, size);
	}

	/* 逐步将每个最大值的根结点与末尾元素交换,并且剩余顶点再调整成大顶推*/
	for(i=size; i > 1; i--)
	{
		swap(a, 1, i);

		HeapAdjust(a, 1, i-1);
	}
}

int main()
{
	int array[] = {-1, 21, 25, 49, 21, 16, 8};  //array[0]不作为排序元素,哨兵
	int len = sizeof(array) / sizeof(*array);

	int size = len -1;
	println(array, len);

	HeapSort(array, size);

	println(array, len);

	return 0;
}


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值