当前位置: 首页 > article >正文

八大排序算法——堆排序

目录

前言

一、向上调整算法建堆

二、向下调整算法建堆 

三、堆排序


前言

        堆排序是基于堆结构的一种排序思想,因此要为一个乱序的数组进行排序的前提是数组必须要是一个堆,所以要先对数组进行建堆操作


一、向上调整算法建堆

        时间复杂度:O( n*logn )

         由于向上调整算法建堆的时间复杂度的证明太过晦涩难懂,还要涉及数学中的错位相减法,所以这里就不证明了,感兴趣的可以自己去了解一下

        这里只需要知道向上调整算法建堆的时间复杂度为 O( n*logn )

//交换两个数的位置
void sweap(int* num1, int* num2)
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}
//向上调整算法(大根堆)
void AdjustUp(int* arr, int pos)
{
	//当前调整的位置不能是堆顶
	if (pos == 0)
	{
		return;
	}
	//寻找双亲节点
	int parents = (pos - 1) / 2;
	//当前位置与双亲节点进行比较
	//如果当前位置的数大于双亲节点,就进行交换,并且继续向上调整
	//如果当前位置的数小于双亲节点,表示堆已经构建好了
	if (arr[parents] < arr[pos])
	{
		//交换两个数位置
		sweap(&arr[parents], &arr[pos]);
		//继续向上调整
		AdjustUp(arr, parents);
	}
}
int main()
{
	//给定一个乱序数组
	int arr[] = { 8,3,2,6,7,1,4,9,5 };
	//计算数组元素个数
	int size = sizeof(arr) / sizeof(arr[0]);
	//向上调整算法建堆
	//从前往后依次调整建堆
	//先让节点之前的数为堆,然后整体为堆
	for (int i = 0; i < size; i++)
	{
		AdjustUp(arr, i);
	}
	return 0;
}

二、向下调整算法建堆 

         时间复杂度:O( n )

        由于向下调整算法建堆的时间复杂度的证明太过晦涩难懂,还要涉及数学中的错位相减法,所以这里就不证明了,感兴趣的可以自己去了解一下

        这里只需要知道向下调整算法建堆的时间复杂度为 O( n )        

//交换两个数的位置
void sweap(int* num1, int* num2)
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}
//向下调整算法(大根堆)
void AdjustDown(int* arr, int size, int pos)
{
	//左孩子位置
	int child = pos * 2 + 1;
	//向下调整算法,直到左孩子位置大于数组个数
	if (child < size)
	{
		//选出左右孩子中最大的那个孩子
		if (child + 1 < size && arr[child] < arr[child + 1])
		{
			child++;
		}
		//与当前位置进行比较
		//如果左右孩子中最大数大于当前位置的数,就进行交换,并且继续向下调整
		//如果左右孩子中最大数小于当前位置的数,表示堆已经调整好了
		if (arr[child] > arr[pos])
		{
			//交换两个数的位置
			sweap(&arr[pos], &arr[child]);
			//继续向下调整
			AdjustDown(arr, size, child);
		}
	}
}
int main()
{
	//给定一个乱序数组
	int arr[] = { 8,3,2,6,7,1,4,9,5 };
	//计算数组元素个数
	int size = sizeof(arr) / sizeof(arr[0]);
	//向上调整算法建堆
	//从最后一个叶子节点父节点往前依次调整建堆
	//先让节点的左右子树为堆,然后整体为堆
	int pos = (size - 1) / 2;//最后一个叶子节点父节点
	for (int i = pos; i >= 0; i--)
	{
		AdjustDown(arr, size, i);
	}
	return 0;
}

三、堆排序

         时间复杂度:O( n*logn )

         在进行建堆操作时我们可以选择向上调整算法和向下调整算法,但是由于向下调整算法的时间复杂度要优于向上调整算法,因此更推荐使用向下调整算法建堆

        建堆的时间复杂度为O( n )每次调整的堆结构的时间复杂度为O( logn ) ,因此整体时间复杂度为O( n*logn )

堆排序的过程大致如下:

  1. 将待排序的数组构造成一个大顶堆(或小顶堆,根据需要)。此时,整个数组的最大值(或最小值)就是堆结构的顶端
  2. 将顶端的数与末尾的数交换。此时,末尾的数为最大值(或最小值),剩余待排序数组个数为n-1
  3. 将剩余的n-1个数再构造成大顶堆(或小顶堆),再将顶端数与n-1位置的数交换。如此反复执行,便能得到有序数组

【注意】

  • 排升序要建大堆
  • 排降序要建小堆 

        整体代码实现 

//交换两个数的位置
void sweap(int* num1, int* num2)
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}

//向下调整算法(大根堆)
void AdjustDown(int* arr, int size, int pos)
{
	//左孩子位置
	int child = pos * 2 + 1;
	//向下调整算法,直到左孩子位置大于数组个数
	if (child < size)
	{
		//选出左右孩子中最大的那个孩子
		if (child + 1 < size && arr[child] < arr[child + 1])
		{
			child++;
		}
		//与当前位置进行比较
		//如果左右孩子中最大数大于当前位置的数,就进行交换,并且继续向下调整
		//如果左右孩子中最大数小于当前位置的数,表示堆已经调整好了
		if (arr[child] > arr[pos])
		{
			//交换两个数的位置
			sweap(&arr[pos], &arr[child]);
			//继续向下调整
			AdjustDown(arr, size, child);
		}
	}
}

//堆排序——升序
void HeapSort(int* arr, int size)
{
	//从后往前依次调整建堆
	//先让节点的左右子树为堆,然后整体为堆
    int pos = (size - 1) / 2;//最后一个叶子节点父节点
	for (int i = pos; i >= 0; i--)
	{
		//向下调整建堆
		AdjustDown(arr, size, i);
	}
	//堆排序
	//排升序要建大堆
	//排降序要建小堆
	for (int i = 0; i < size; i++)
	{
		//堆顶与最后一个有效元素交换位置
		sweap(&arr[0], &arr[size - 1 - i]);
		//向下调整,保持堆的结构
		AdjustDown(arr, size - i - 1, 0);
	}
}

int main()
{
	//给定一个乱序数组
	int arr[] = { 8,3,2,6,7,1,4,9,5 };
	//计算数组元素个数
	int size = sizeof(arr) / sizeof(arr[0]);
	//堆排序
	HeapSort(arr, size);
	//打印排序后的数据
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 


http://www.kler.cn/a/370460.html

相关文章:

  • 在 Vue 3 项目中集成和使用 vue3-video-play
  • 动手学大数据-3社区开源实践
  • 【大数据】机器学习------支持向量机(SVM)
  • ASP .NET Core 学习(.NET9)配置接口访问路由
  • 深度学习:大模型Decoding+MindSpore NLP分布式推理详解
  • 【青蛙过河——思维】
  • R语言机器学习算法实战系列(十三)随机森林生存分析构建预后模型 (Random Survival Forest)
  • Flutter Image和Text图文组件实战案例
  • vue使用高德地图实现轨迹显隐
  • 第6次CCF CSP认证真题解
  • CSS.导入方式
  • 字符串及正则表达式
  • vue 果蔬识别系统百度AI识别vue+springboot java开发、elementui+ echarts+ vant开发
  • 已经安装好Ubuntu,10分钟配好Anaconda3
  • Tomcat作为web的优缺点
  • 【前端基础】如何判断鼠标选中文本的方向
  • linux tracepoint
  • x3daudio17dll丢失是什么原因?如何重新安装
  • Centos7.9编译安装Python3.12
  • 如何在Linux下安装和配置Docker
  • 七,Linux基础环境搭建(CentOS7)- 安装Scala和Spark
  • Ubuntu 20.04 安装 OpenCV 和 OpenCV_contrib 教程
  • 计算机网络关键名词中英对照
  • WebGIS开发之编辑功能(分割、融合、捕捉、追踪)
  • 【QT】HTTP服务器
  • 数据挖掘:电商会员价值分析模型方案