iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++超详细分析优化排序算法之堆排序
  • 232
分享到

C++超详细分析优化排序算法之堆排序

C++堆排序C++优化排序 2023-02-09 09:02:41 232人浏览 独家记忆
摘要

堆排序,学习了整整一天才把这个排序彻底搞明白…… 首先第一点,堆排序是直接选择排序的一种优化排序算法。由于直接排序算法的遍历次数过多,导致直接排序算法的时

排序学习了整整一天才把这个排序彻底搞明白……

首先第一点,堆排序是直接选择排序的一种优化排序算法。由于直接排序算法的遍历次数过多,导致直接排序算法的时间复杂度为O(N^2),不适合排大量数据,堆排序应运而生。

堆排序(Heap Sort)进行的改进是能够保存一部分在每次遍历整个数组找出最大(小)值、次大(小)值,主要利用的就是完全二叉树这种数据结构。(后面说是如何保存这些数据的)

堆排序最重要的知识点无非两个:

1、向下调整算法

2、堆的逻辑结构是一棵完全二叉树

先从定义开始学习:

向下调整算法:顾名思义就是从上到下进行数据的调整,可以将完全二叉树调整为最大堆与最小堆(这两种堆也同时被称为“大顶堆”和“小顶堆”)这种算法的前提是:根节点的左右两棵子树均以建成最大(小)堆。

最大堆:所有的父节点都大于子结点

最小堆:所有的父节点都小于子结点

完全二叉树:从上到下、从左到右依次排列的一种树(即从第一层到第n-1层都是满的,只有第n层不满且从左到右排列数据)

(以建小堆为例)看一种典型的示例:

向下调整算法就是处理这种完全二叉树的一种算法,经过这种算法可将此数组建成最小堆。

先从根节点开始处理:

9 为父(根)节点,0,1都是其子节点,0 < 1;所以将0与9作一次交换;父节点同时下移至子节点,子节点变为新父节点的子节点:(p = parent, c = child)

9 为父(根)节点,2,3都是其子节点,2 < 3;所以将2与9作一次交换;父节点同时下移至子节点,子节点变为新父节点的子节点:

9 为父(根)节点,6 是其子节点,6< 9;所以将6与9作一次交换;父节点同时下移至子节点,子节点变为新父节点的子节点:

发现此时新的子节点已经越界,故停止向下调整;整个堆现已完成建堆成为最小堆!

这便是所谓的“向下调整算法”。

了解了以上知识后,还得知道父节点与子结点的表示方法:

leftchild = parent * 2 + 1;

rightchild = parent * 2 + 2;

parent = (leftchild - 1) /2;

下面代码实战:

//向下调整:
//根节点左右子树必须已经成堆
void AdjustDown(int a[], int n, int parent)
{
	int child = parent * 2 + 1;
	//左孩子不能越界
	while (child < n)
	{
		//如果只有左孩子,那就不用判断两个孩子的大小,直接判断左孩子和父亲的大小
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		//向下调整
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

简单的交换函数:

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

堆排序的思想现在已经有了雏形:

将一个数组想象成堆,建堆,然后将堆顶最大(小)值置于堆底作为有序数据,这时会新形成一个堆,比之前的堆少一个数据,并且只有根节点的那棵小树未成堆,左右子树已形成大(小)堆,用一次向下调整算法即可将新堆再次建成最大(小)堆。

现在的问题是我们选择建一个最大堆还是最小堆呢?

我们不妨假设建了最小堆,也即上面我们刚刚构建好的堆:

不难发现这样是将最小值筛选出来,再向下调整,选出次小值,这样一来会得到降序的一个数组,反之,若使用最大堆,会得到一个升序的数组。

我们建大堆来得到一个升序数组,现有此无序数组:

//数组
int a[] = { 5,9,6,1,7,2,0,4,3,8 };
//元素个数
int n = (int)sizeof(a) / sizeof(a[0]);

第一步就是建堆:

我们会发现:这样“不听话”的数组显然不符合向下调整算法的前提条件,所以我们可以从这个数组中找能用这个算法的地方:从后向前去调整,最后一个叶子节点?一个数据,不需要调整;

最后一个父节点?他将会有0-2个子节点,而且只有这三个数据,不管怎么“不听话”,这个最小单位会满足“根的左右子树成堆”的这个条件,下一次再将这个父节点-1,即可实现对前一个父节点进行向下调整,循环此步骤直至真正的根节点,这时整个数组会被建成最大堆。

void HeapSort(int a[], int n)
{
    //建堆
	int parent = (n - 1 - 1) / 2;
	while (parent >= 0)
	{
		AdjustDown(a, n, parent);
		parent--;
	}
}

第二步就是排序:

建成堆后,我们需要进行数据的交换形成有序数据区。

void HeapSort(int a[], int n)
{
    //建堆
	int parent = (n - 1 - 1) / 2;
	while (parent >= 0)
	{
		AdjustDown(a, n, parent);
		parent--;
	}
	//已经成最大堆,不用再从最后一个父节点建堆
	//每次只用改变根节点的堆(根左右堆已为最大堆)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

堆排序完毕!

整个代码分享:

#include <stdio.h>
void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//向下调整:
//根节点左右子树必须已经成堆
void AdjustDown(int a[], int n, int parent)
{
	int child = parent * 2 + 1;
	//左孩子不能越界
	while (child < n)
	{
		//如果只有左孩子,那就不用判断两个孩子的大小,直接判断左孩子和父亲的大小
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		//向下调整
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int a[], int n)
{
	int parent = (n - 1 - 1) / 2;
	while (parent >= 0)
	{
		AdjustDown(a, n, parent);
		parent--;
	}
	//已经成最大堆,不用再从最后一个父节点建堆
	//每次只用改变根节点的堆(根左右堆已为最大堆)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}
void print(int* a, int n)
{
	int i = 0;
	for (i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
int main()
{
	int a[] = { 5,9,6,1,7,2,0,4,3,8 };
	int n = (int)sizeof(a) / sizeof(a[0]);
	HeapSort(a, n);
	print(a, n);
	return 0;
}

到此这篇关于c++超详细分析优化排序算法之堆排序的文章就介绍到这了,更多相关C++堆排序内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++超详细分析优化排序算法之堆排序

本文链接: https://www.lsjlt.com/news/195279.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++超详细分析优化排序算法之堆排序
    堆排序,学习了整整一天才把这个排序彻底搞明白…… 首先第一点,堆排序是直接选择排序的一种优化排序算法。由于直接排序算法的遍历次数过多,导致直接排序算法的时...
    99+
    2023-02-09
    C++堆排序 C++优化排序
  • Python排序算法之堆排序算法
    目录1. 树满二叉树的特性:什么是完全二叉树?完全二叉树的专业概念:2. 二叉堆2.1 二叉堆的抽象数据结构2.2 API 实现3. 堆排序4. 后记本文从树数据结构说到二叉堆数据结...
    99+
    2023-01-07
    python堆排序算法实现 堆排序算法以及python实现 python 堆排序算法
  • JAVA十大排序算法之堆排序详解
    目录堆排序知识补充二叉树满二叉树完全二叉树二叉堆代码实现时间复杂度算法稳定性思考总结堆排序 这里的堆并不是JVM中堆栈的堆,而是一种特殊的二叉树,通常也叫作二叉堆。它具有以下特点: ...
    99+
    2024-04-02
  • Java十大排序算法之堆排序刨析
    二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性︰ 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最...
    99+
    2024-04-02
  • C++超详细实现堆和堆排序过像
    目录有关堆C++实现堆堆的应用堆排序有关二叉树的性质: 1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点. 2. 若规定根节点的层数为1,则深度为h的二叉树的最...
    99+
    2024-04-02
  • 图解Java排序算法之堆排序
    目录预备知识堆排序堆堆排序基本思想及步骤再简单总结下堆排序的基本思路:总结预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均...
    99+
    2024-04-02
  • C语言排序算法之选择排序(直接选择排序,堆排序)
    目录前言一、直接选择排序1.1 算法思想1.2 代码实现1.3 直接选择排序的特征总结二、堆排序2.1 什么是堆?2.2 判断是否是堆2.3 向下调整算...
    99+
    2024-04-02
  • 超详细解析C++实现归并排序算法
    目录一、前言分治算法分治算法解题方法二、归并排序1.问题分析2.算法设计3.算法分析三、AC代码一、前言 分治算法 归并排序,其实就是一种分治算法 ,那么在了解归并排序之前,我们先来...
    99+
    2024-04-02
  • C语言数据结构之堆排序的优化算法
    目录1.堆排序优化算法1.1建堆的时间复杂度1.1.1 向下调整建堆:O(N)1.1.2 向上调整建堆:O(N*logN)1.2堆排序的复杂度1.2.1原堆排序的时间复杂度...
    99+
    2024-04-02
  • 分析Java排序算法之希尔排序
    这篇文章主要介绍“分析Java排序算法之希尔排序”,在日常操作中,相信很多人在分析Java排序算法之希尔排序问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分析Java排序算法之希尔排序”的疑惑有所帮助!接下来...
    99+
    2023-06-25
  • Java排序算法之堆排序如何实现
    这篇文章主要介绍了Java排序算法之堆排序如何实现,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。二叉堆是完全二叉树或者是近似完全二叉树。二叉堆满足二个特性︰1.父结点的键值总...
    99+
    2023-06-21
  • Java 归并排序算法、堆排序算法实例详解
    基本思想:  归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。归并排序示例:合并方法:设r[i…n]由两个有序子表r[i…m...
    99+
    2023-05-31
    java 归并排序 堆排序
  • 超详细解析C++实现快速排序算法的方法
    目录一、前言1.分治算法2.分治算法解题方法二、快速排序1.问题分析2.算法设计3.算法分析三、AC代码一、前言 1.分治算法 快速排序,其实是一种分治算法,那么在了解快速排序之前,...
    99+
    2024-04-02
  • 排序算法图解之Java冒泡排序及优化
    目录1.冒泡排序简介2.图解算法3.冒泡排序代码实现4.冒泡排序算法的优化1.冒泡排序简介 冒泡排序(Bubble Sorting)即:通过对待排序的序列从前往后,依次比较相邻元素的...
    99+
    2022-11-13
    Java冒泡排序 Java 排序
  • Python排序算法之插入排序及其优化方案详解
    一、插入排序 插入排序与我们平时打扑克牌非常相似,将新摸到的牌插入到已有的牌中合适的位置,而已有的牌往往是有序的。 1.1 执行流程 (1)在执行过程中,插入排序会将序列分为2部...
    99+
    2024-04-02
  • 排序算法之希尔排序法解析
    目录什么是希尔排序法希尔排序法与插入排序法之间的区别与联系代码演示对比什么是希尔排序法 希尔排序法(Shell Sort),也称为缩小增量排序,是一种改进的插入排序算法。它通过将待排...
    99+
    2023-08-08
    希尔排序算法 希尔排序法
  • C语言超详细讲解排序算法上篇
    目录1、直接插入排序2、希尔排序(缩小增量排序)3、直接选择排序4、堆排序进入正式内容之前,我们先了解下初阶常见的排序分类 :我们今天讲前四个! 1、直接插入排序 基本思...
    99+
    2024-04-02
  • C语言超详细讲解排序算法下篇
    目录1、冒泡排序2、快速排序 ( 三种方法 )3、归并排序4、排序算法复杂度及稳定性分析 上期学习完了前四个排序,这期我们来学习剩下的三个排序 1、冒泡排序 &n...
    99+
    2024-04-02
  • 排序算法之插入排序法解析
    目录什么是插入排序法算法优化心得体会什么是插入排序法 插入排序法是一种简单但有效的排序算法,其基本思想是将一个待排序的元素逐个插入到已经排好序的元素序列中,直至所有元素都被插入完成,...
    99+
    2023-08-08
    排序算法 插入排序法
  • C#算法之冒泡排序、插入排序、选择排序
    冒泡排序法 是数组等线性排列的数字从大到小或从小到大排序。 以从小到大排序为例。 数据 11, 35, 39, 30, 7, 36, 22, 13, 1, 38, 26, 18, 1...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作