排序算法——堆排序

堆排序

文章目录

  • 堆排序
      • 注:孩子第一次写博客,以后会进步的,希望各位能够给孩子一个小小的关注,激励我写出更多更好的优质文章
  • 1.基本概念
  • 2.堆排序的思想
  • 3.编写难点
    • 3.1 注意
  • 4.源代码

注:孩子第一次写博客,以后会进步的,希望各位能够给孩子一个小小的关注,激励我写出更多更好的优质文章

1.基本概念

  • 大顶堆:父节点的值大于子节点

  • 小顶堆:父节点的值小于子节点(如下图所示)

  • 排序算法——堆排序_第1张图片

  • 二叉树:每个节点最多只能有两棵子树,且有左右之分

  • 完全二叉树:若一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树。

  • 满二叉树: 除了叶节点以外,其余每个节点都有两个子节点

  • 树高 :树的层数

  • 叶子节点:度为0的节点,也就是最外层的节点

  • 非叶子节点:度不为0的节点

2.堆排序的思想

 若要进行升序排列,则使用大顶堆,先将待排序列构造成一个完全二叉树,然后将其调整为一个大顶堆,此时在大顶堆中根节点是整个序列中最大值,将其与最后一个节点交换,这时尾节点就是最大值,然后将尾节点剔除出整个序列,会得到一个n-1的序列,然后再次调整为大顶堆(因为只进行了首尾交换,所以调整时从根节点开始调整,不用像第一次那样从最后一个非叶子节点开始)循环往复,直至只剩下根节点为止,堆排序结束。

排序算法——堆排序_第2张图片
很明显,第一次从最后一个非叶子节点开始,第一个非叶子节点是8,8比12小,与其交换;然后比较倒数第二个非叶子节点,找到最大的子节点与其交换,即21与6交换;最后到根节点,其子节点较大的是21,与15交换得到右图。
排序算法——堆排序_第3张图片

3.编写难点

  • 排序算法——堆排序_第4张图片

3.1 注意

第一次调整为最大堆时最麻烦,需要从倒数第一个非叶子节点开始直到根节点,调整函数的参数 start和end分别是(len-1-1)/2 和len-1
排序算法——堆排序_第5张图片
调整函数的基本思想:
排序算法——堆排序_第6张图片

4.源代码

//堆排序的单次调整  (通过start和end来限定大顶堆中要处理的框框)
//时间复杂度O(logn)   空间复杂度O(1)   
void Heap_Adjust(int *arr, int len, int start, int end)
{
	int tmp = arr[start];
	for(int i=start*2+1; i<=end; i=i*2+1)//难点3   //i=start*2+1 这里可以体现出时间复杂度
	{
		//判断,当前空白格子是否存在右孩子,如果右孩子存在且大于左孩子,则让i指向较大孩子
		if(i+1<=end && arr[i+1] > arr[i])
		{
			i++;
		}
		//这个if执行结束,i肯定指向空白格子的较大孩子
		if(arr[i] > tmp)//较大孩子值还大于父节点,向上挪动
		{
			arr[start] = arr[i];//将较大孩子值挪动到当前空白格子,则出现新的空白格子
			start = i;//出现新的空白格子,用start指向
		}
		else
		{
			arr[start] = tmp;
			break;
		}
	}

	//触底了,tmp的值,也需要放回来,放回到arr[start]
	arr[start] = tmp;
	}
//堆排序(升序:大顶堆) 时间复杂度O(nlogn) 空间复杂度O(1) 稳定性:不稳定
//堆排序适用场景:需要找前3个大值,或者前3个小值  
void Heap_Sort(int *arr, int len)
{
	//1.将数组中的数据臆想成完全二叉树,代码层次不用管 
	//2.第一次调整比较麻烦(从最后一个非叶子节点框框开始,从右向左,从下向上去调整)
	//最后一个非叶子节点下标怎么求?  解:通过尾结点的下标(len-1),子推父((i-1)/2),从而得到最后一个非叶子节点下标((len-1-1)/2)
	for(int i=(len-1-1)/2; i>=0; i--)//i指向框框的开始节点的下标
	{
		Heap_Adjust(arr, len, i, len-1); //难点1:第四个参数没有规律,则直接给最大值len-1即可
	} 
	//3.此时,经过第2步的调整,已经是一个大顶堆了
	    //将根节点的值和当前尾结点的值进行交换,然后将尾结点剔除出排序(因为这时尾结点的值已经有序)
	for(int i=0; i<len-1; i++)//i代表次数 也代表当前根节点的下标
	{
		//根节点和当前尾结点进行交换
		int tmp = arr[0];
		arr[0] = arr[len-1-i];
		arr[len-1-i] = tmp;
				//第4步:重复2,3,调整简单,只需要调整最大的框框
		//len-1-i代表这一趟排序中尾节点的下标,
		//这一趟结束的时候,需要将尾结点剔除出排序,所以需要(len-1-i)-1
		Heap_Adjust(arr, len, 0, (len-1-i)-1);//难点2 
	}
}

你可能感兴趣的:(基础数据结构,排序算法,算法,数据结构)