C语言堆排序的实现

堆排序是一种树形选择排序,在排序过程中,将数组a[]看成一棵完全二叉树,利用双亲节点和孩子节点之间的内在关系,在当前无序的序列中选择关键字最大(或最小)的排序。其空间复杂度为O(1),在最坏的情况下时间复杂度为O(nlog2n)。堆排序是一种不稳定的算法,且只能用于顺序结构,不能用于链式结构;初始建堆所需的比较次数较多,因此记录少的时候不宜采用。堆排序在最坏情况下的时间复杂度比快速排序下最坏的时间复杂度O(n2)更为优秀,当记录比较多的时候较为高效。

下面实现代码:

首先是预定义和类型定义:

#define OK 1
#define ERROR 0

typedef int Status;
typedef int ElemType;

typedef struct{
	ElemType *data;
	int length;
}SqList;

顺序表的插入:

Status EnSqList(SqList *L,ElemType e,int n)
{
	if (L->length > n)
		return ERROR;
	L->data[L->length + 1] = e;
	L->length++;
	return OK;
}

筛选法调整堆:

void HeapAdjust(SqList *L, int s, int m)
{
	int j;
	ElemType rc;
	rc = L->data[s];
	for (j = 2 * s; j <= m; j *= 2)
	{
		if (j < m&&L->data[j] < L->data[j + 1])
			j++;
		if (rc>=L->data[j])
			break;
		L->data[s] = L->data[j];
		s = j;
	}
	L->data[s] = rc;
}

声明rc用于储存下标为s的元素的值。初始化j为2*s,使j指向s的左子树,当j小于或等于最大上限m的时候,执行循环:如果j小于m并且下标为j的元素小于其后一个元素时,让j加1使j指向下一个元素,即在s的左右子树总选取最大值并在j中记录其下标;如果左右子树中最大值小于rc的值,则跳出循环,此时s指向rc应该储存的位置,即其双亲节点大于rc,其左右子树节点均小于rc;若左右子树中最大值大于rc的值,则让其子树节点j的值赋值给双亲节点s,然后让s指向其子树节点j。

跳出循环后让rc的值赋值给下标为s的节点。

建初堆:

void CreatHeap(SqList *L)
{
	int i;
	for (i = L->length / 2; i >= 1; i--)
		HeapAdjust(L, i, L->length);
}

从最后一个节点的双亲节点开始,逐步调用HeapAdjust()以创建大根堆,以确保以i为双亲节点的树是大根堆(从图上来看,是从底层到顶层创建大根堆的做法)。

堆排序算法的实现:

void HeapSort(SqList *L)
{
	int i;
	ElemType x;
	CreatHeap(L);
	for (i = L->length; i > 1; --i)
	{
		x = L->data[1];
		L->data[1] = L->data[i];
		L->data[i] = x;
		HeapAdjust(L, 1, i - 1);
	}
}

先引用CreatHeap()函数对数组进行排序,使其成为大根堆,而后,交换下标为1和最后一个元素(即下标i元素)的值,因为堆排序的结果得到的是一个小根堆,并且在数组中呈递增,,而此时下标为1的元素保存着最大元素的值,而最后一个元素(下标为i的元素)保存着最小元素的值,故将其对调后,最后一个元素(下标为i的元素)保存的必然是最大元素,已经达到目的位置,让i减一(往前移动一位),令原来i的前一位为最后一个数据继续进行堆排序(类似于将未排序完成的元素作为一个数组,排序完成的元素作为一个数组,排序时不对已经排序完成的数组进行操作,仅仅对未排序的数组进行堆排序,结束的时候将最后一位,即排序归并到排序完成的数组中)。

加入main()函数:

int main(void)
{
	SqList L;
	ElemType e;
	int i, n;
	L.length = 0;
	printf("输入元素个数:");
	scanf("%d", &n);
	L.data = (int *)malloc(sizeof(int)*n);
	srand((int)time(0));
	for (i = 0; i < n; i++)
	{
		e = rand();
		EnSqList(&L, e, n);
	}
	printf("排序前数组:");
	for (i = 0; i < L.length; i++)
		printf("%d ", L.data[i + 1]);
	printf("\n");
	HeapSort(&L);
	printf("排序后数组:");
	for (i = 0; i < L.length; i++)
		printf("%d ", L.data[i + 1]);
	printf("\n");
	return 0;
}







  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值