堆排序(解析)

开搞

实际上是对完全二叉树的操作,先生成大根堆(该节点的子节点均小于该节点),

再逐步将头节点与尾节点交换,交换后堆化二叉树,又变成大根堆,重复操作,直到heapSize = 0

实现大根堆

用户每次输入一个数,经过与头节点比较做交换处理

//大根堆
void heapInsert(int a[], int Index) {
	while (a[Index] > a[(Index - 1) / 2]) {
		swap(a[Index], a[(Index - 1) / 2]);
		Index = (Index - 1) / 2;
	}
}

实现堆化

//前提是这颗二叉树已经是大根堆
//当我们改变某个以Index为下标节点的值后,heapify使下标以Index为头节点的完全二叉树 重新 堆化
void heapify(int a[], int Index, int heapSize) {
	int left = (Index * 2) + 1;//左节点下标
	while (left < heapSize) {
		int right = ((Index * 2) + 2);//右节点
		int biggest = (right < heapSize) && (a[right] > a[left]) ? right : left;//判断右节点是否存在,存在则比左右大小,返回大值下标
		biggest = a[Index] > a[biggest] ? Index : biggest;//把左右孩子中较大值的下标和父节点比较,返回较大者的下标
		if (a[Index] == a[biggest])break;//如果较大值的下标就是头节点,说明已经形成大根堆,跳出循环
		swap(a[Index], a[biggest]);
		Index = biggest;
		left = (Index * 2) + 1;
	}
}

实现堆排序

逐步将头节点与尾节点交换,交换后堆化二叉树,又变成大根堆,重复操作,直到heapSize = 0

这样[heapSize,a.length]就是有序的

//堆排序
//大根堆
void heapInsert(int a[], int Index) {
	while (a[Index] > a[(Index - 1) / 2]) {
		swap(a[Index], a[(Index - 1) / 2]);
		Index = (Index - 1) / 2;
	}
}

//前提是这颗二叉树已经是大根堆
//当我们改变某个以Index为下标节点的值后,heapify使下标以Index为头节点的完全二叉树 重新 堆化
void heapify(int a[], int Index, int heapSize) {
	int left = (Index * 2) + 1;//左节点下标
	while (left < heapSize) {
		int right = ((Index * 2) + 2);//右节点
		int biggest = (right < heapSize) && (a[right] > a[left]) ? right : left;//判断右节点是否存在,存在则比左右大小,返回大值下标
		biggest = a[Index] > a[biggest] ? Index : biggest;//把左右孩子中较大值的下标和父节点比较,返回较大者的下标
		if (a[Index] == a[biggest])break;//如果较大值的下标就是头节点,说明已经形成大根堆,跳出循环
		swap(a[Index], a[biggest]);
		Index = biggest;
		left = (Index * 2) + 1;
	}
}

//堆排序
//将大根堆的头节点交换到堆尾部,--heapSize;当heapSize==0时数组有序
void heapSort(int a[], int heapSize) {
	//形成大根堆
	for (int i = 0; i < heapSize; i++) heapInsert(a, i);
	while (heapSize) {
		//交换头尾节点
		swap(a[0], a[--heapSize]);
		//堆化
		heapify(a, 0, heapSize);
	}

}

时间复杂度O(Nlogn),空间复杂度O(1);

To see an oasis of place

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值