栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

八大排序详解(三):堆排序(超详细)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

八大排序详解(三):堆排序(超详细)

1.堆排序:堆排序是按照堆的数据结构来进行排序 并且这种数据结构称为完全二叉树。

大顶堆:父节点值大于孩子节点 升序排列用大顶堆

小顶堆:父节点值小于孩子节点 降序排列用小顶堆

2.堆排序原则:

将数组先臆想成二叉树,然后调整为大顶堆,接着向根节点的值和尾结点进行交换,交换完毕将当前根节点排除我们整个排序过程,直到二叉树只剩下一个节点,具体原则流程见下图:

         

3.堆排序代码实现

补充:推子节点和父节点关系    如果父节点下标是i 则子节点下标是2i+1

子节点下标是i   父节点下标是(i-1)/2

void Heap_Adjust(int* arr, int len, int start, int end)
{
	//将start这个下标的值  拷贝到tmp  
	int tmp = arr[start];           //难点4:i=start*2+1   
	for (int i = start * 2 + 1; i <= end; i = start * 2 + 1)//i代表左孩子的下标
	{
		if (i + 1 <= end && arr[i + 1] > arr[i]) //i+1代表右孩子下标
		{           //如果左右孩子都存在,且右孩子的值大于左孩子,则让i指向右孩子
			i++;
		}
		//此时i肯定指向较大的孩子节点

		if (arr[i] > tmp)//较大孩子的值 还大于 父节点的值
		{
			arr[start] = arr[i];
			start = i;         //难点5:start要指向新的空白格子
		}
		else
		{
			break;
		}
	}
	arr[start] = tmp;     //难点6:  什么时候将tmp放回数组?
						   //两种情况: 1.空白格子没有孩子节点   
							//          2.有孩子节点,但是孩子节点值小于tmp
}


//堆排序   

void Heap_Sort(int* arr, int len) //单独Heap_Sort是O(n)
{
	//从最后一个非叶子节点开始,由内到外开始调整   //难点1:(len-1-1)/2理解: 子节点是len-1 其父节点是(len-1-1)/2
        
	for (int i = (len - 1 - 1) / 2; i >= 0; i--)//i保存非叶子节点的下标
	{                                    //难点3  len-1(饱和式救援)	
		Heap_Adjust(arr, len, i, len-1);//这里,第四个参数end没有规则,因为每次调整的那个小框的最后一个子节点下标无法确定   所以直接给尾结点下标len-1即可
	}

	//将顶部根节点的值(0号下标)和当前最后一个节点值(len-1-i号下标)进行交换
	for (int i = 0; i < len - 1; i++)
	{
		int tmp = arr[0];
		arr[0] = arr[len - 1 - i];
		arr[len - 1 - i] = tmp;

		//这里,调整只需要一次即可(最外面的框)  难点2:(len-1-i)-1
		Heap_Adjust(arr, len, 0, (len - 1 - i) - 1);//len-1-i  代表这一趟的最后一个节点下标   这个节点这一趟处理结束后,就不再需要了
	}

}

 4.总结:堆排序属于排序中较难的一种,一定要对比图去理解。堆排序的时间复杂度是O(nlogn)  空间复杂度O(1)   稳定性:不稳定(存在跳跃交换)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/879766.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号