堆排序---图文并茂

大堆与小堆

二者都是完全二叉树。
大堆:父节点的值总是大于或等于子节点
大堆:父节点的值总是小于或等于子节点
int child = parent * 2 + 1; (父节点与子节点下标关系)

堆的逻辑结构和物理结构的关联

物理结构是一个数组,而逻辑结构是一个完全二叉树。
两结构的对应关系

堆排序的思路(分两步)

例子如下:现有数组a[]={1,9,3,4,8,3},要将其升序排列。
在这里插入图片描述

第一步

第一步:要求升序,则将其原堆建为大堆
    若要求降序,则将其原堆建为小堆
   (原因在最后会讲)

如何将原堆建为大堆?
用大白话讲就是:
先找到最后一层最右边的那一个叶子节点a,再找a的父节点b,从b开始进行向下调整操作,然后遍历数组,重复向下调整操作(下标减小,直到<0结束)。
在这里插入图片描述

在这里插入图片描述

向下调整操作的代码:

void AdjustDown(int* a, int n, int parent)  //  n是 要调整的堆 的 最后一个数 的下标+1 
{                                           //parent就是图中的父节点的下标
	int child = parent * 2 + 1;            
	while (child < n)
	{
		// 选出左右孩子中小/大的那个(假设法)
		if (child + 1 < n
			&& a[child + 1] > a[child])  //child + 1 < n确保有右孩子才进行比较,防越界
		{
			++child;  //此时孩子为右孩子
		}

		if (a[child] > a[parent])
		{
			Swap(&a[parent], &a[child]);   //父子交换
			parent = child;
			child = parent * 2 + 1;   //父子向下更替
		}
		else
		{
			break;    
		}
	}
}

纵观全过程,每一个进行向下调整操作的数,其左子树和右子树都是大堆,其实这就是向下调整操作能进行的前提条件。

第二步

第二步:堆顶与最后一个数进行交换,将最后一个数不看做堆里的数(堆里的数减少一个),在堆顶处进行向下调整操作。重复操作,直到堆里没有数。此刻,整个数组已有序,堆排序完成。
在这里插入图片描述

第一步的若要求升序,则将其原堆建为大堆
      若要求降序,则将其原堆建为小堆 在这里就明白了:
因为堆顶与最后一位进行了交换,那么最大值其实在最后一位。

堆排序的代码(升序)

#include<stdio.h>

void Swap(int* p1, int* p2)   //交换函数
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


void AdjustDown(int* a, int n, int parent)  //  n是 要调整的堆 的 最后一个数 的下标+1 
{                                           //parent就是图中的父节点的下标
	int child = parent * 2 + 1;            
	while (child < n)
	{
		// 选出左右孩子中小/大的那个(假设法)
		if (child + 1 < n
			&& a[child + 1] > a[child])     //child + 1 < n确保有右孩子才进行比较,防越界
		{
			++child;  //此时孩子为右孩子
		}

		if (a[child] > a[parent])
		{
			Swap(&a[parent], &a[child]);   //父子交换
			parent = child;
			child = parent * 2 + 1;   //父子向下更替
		}
		else
		{
			break;    
		}
	}
}


void HeapSort(int* a, int n)
{
	// 升序 -- 建大堆
	// 降序 -- 建小堆

	// 建堆--向下调整建堆 --O(N)  
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)  //(n - 1 - 1) / 2:文中所指的b点的下标   遍历的过程
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);

		// 再调整,选出次大的数
		AdjustDown(a, end, 0);    //  end是 “要调整的堆” 的 最后一个数 的下标+1 

		--end;       // “要调整的堆” 的 最后一个数一直在变,因为堆中的数在变少
	}
}


int main()
{
	int a[] = {1 ,9 ,3 ,4 ,8 ,3};
	int n = sizeof(a) / sizeof(int);
	HeapSort(a, n);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

执行结果为:
在这里插入图片描述
到这里就结束了,有什么问题和错误,欢迎指出来,博主画图不易,希望得到你的关注和点赞哦!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值