千家信息网

c++怎么实现堆排序

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,这篇文章主要讲解了"c++怎么实现堆排序",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"c++怎么实现堆排序"吧!一 准备知识堆的结构可以分为大根堆和小
千家信息网最后更新 2025年01月23日c++怎么实现堆排序

这篇文章主要讲解了"c++怎么实现堆排序",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"c++怎么实现堆排序"吧!

一 准备知识

堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆

1.1 大根堆和小根堆
性质:每个结点的值都大于其左孩子和右孩子结点的值,称之为大根堆;每个结点的值都小于其左孩子和右孩子结点的值,称之为小根堆。如下图

我们对上面的图中每个数都进行了标记,上面的结构映射成数组就变成了下面这个样子

还有一个基本概念:查找数组中某个数的父结点和左右孩子结点,比如已知索引为i的数,那么

1.父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)

2.左孩子索引:2*i+1

3.右孩子索引:2*i+2

所以上面两个数组可以脑补成堆结构,因为他们满足堆的定义性质:

大根堆:arr(i)>arr(2i+1) && arr(i)>arr(2i+2)

小根堆:arr(i)i+1) && arr(i)i+2)

二 堆排序基本步骤

基本思想:

  1. 首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

  2. 将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

2.1 构造堆

将无序数组构造成一个大根堆(升序用大根堆,降序就用小根堆)

假设存在以下数组

主要思路:第一次保证0~0位置大根堆结构(废话),第二次保证0~1位置大根堆结构,第三次保证0~2位置大根堆结构...直到保证0~n-1位置大根堆结构(每次新插入的数据都与其父结点进行比较,如果插入的数比父结点大,则与父结点交换,否则一直向上交换,直到小于等于父结点,或者来到了顶端)

插入6的时候,6大于他的父结点3,即arr(1)>arr(0),则交换;此时,保证了0~1位置是大根堆结构,如下图:

(友情提示:待交换的数为蓝色,交换后的数为绿色)

插入8的时候,8大于其父结点6,即arr(2)>arr(0),则交换;此时,保证了0~2位置是大根堆结构,如下图

插入5的时候,5大于其父结点3,则交换,交换之后,5又发现比8小,所以不交换;此时,保证了0~3位置大根堆结构,如下图

插入7的时候,7大于其父结点5,则交换,交换之后,7又发现比8小,所以不交换;此时整个数组已经是大根堆结构

2.2 固定最大值再构造堆

此时,我们已经得到一个大根堆,下面将顶端的数与最后一位数交换,然后将剩余的数再构造成一个大根堆

(友情提示:黑色的为固定好的数字,不再参与排序)

此时最大数8已经来到末尾,则固定不动,后面只需要对顶端的数据进行操作即可,拿顶端的数与其左右孩子较大的数进行比较,如果顶端的数大于其左右孩子较大的数,则停止,如果顶端的数小于其左右孩子较大的数,则交换,然后继续与下面的孩子进行比较

下图中,5的左右孩子中,左孩子7比右孩子6大,则5与7进行比较,发现5<7,则交换;交换后,发现5已经大于他的左孩子,说明剩余的数已经构成大根堆,后面就是重复固定最大值,然后构造大根堆

如下图:顶端数7与末尾数3进行交换,固定好7,

剩余的数开始构造大根堆 ,然后顶端数与末尾数交换,固定最大值再构造大根堆,重复执行上面的操作,最终会得到有序数组

三 总结

到这里,大家应该对堆排序都有了自己的见解,我们对上面的流程总结下:

1、首先将无需数组构造成一个大根堆(新插入的数据与其父结点比较)

2、固定一个最大值,将剩余的数重新构造成一个大根堆,重复这样的过程

四 代码

代码中主要两个方法:

1、将待排序数组构造成一个大根堆(元素上升)

2、固定一个最大值,将剩余的数再构造成一个大根堆(元素下降)

    //堆排序    public static void heapSort(int[] arr) {        //构造大根堆        heapInsert(arr);        int size = arr.length;        while (size > 1) {            //固定最大值            swap(arr, 0, size - 1);            size--;            //构造大根堆            heapify(arr, 0, size);         }     }     //构造大根堆(通过新插入的数上升)    public static void heapInsert(int[] arr) {        for (int i = 0; i < arr.length; i++) {            //当前插入的索引            int currentIndex = i;            //父结点索引            int fatherIndex = (currentIndex - 1) / 2;            //如果当前插入的值大于其父结点的值,则交换值,并且将索引指向父结点            //然后继续和上面的父结点值比较,直到不大于父结点,则退出循环            while (arr[currentIndex] > arr[fatherIndex]) {                //交换当前结点与父结点的值                swap(arr, currentIndex, fatherIndex);                //将当前索引指向父索引                currentIndex = fatherIndex;                //重新计算当前索引的父索引                fatherIndex = (currentIndex - 1) / 2;            }        }    }    //将剩余的数构造成大根堆(通过顶端的数下降)    public static void heapify(int[] arr, int index, int size) {        int left = 2 * index + 1;        int right = 2 * index + 2;        while (left < size) {            int largestIndex;            //判断孩子中较大的值的索引(要确保右孩子在size范围之内)            if (arr[left] < arr[right] && right < size) {                largestIndex = right;            } else {                largestIndex = left;            }            //比较父结点的值与孩子中较大的值,并确定最大值的索引            if (arr[index] > arr[largestIndex]) {                largestIndex = index;            }            //如果父结点索引是最大值的索引,那已经是大根堆了,则退出循环            if (index == largestIndex) {                break;            }            //父结点不是最大值,与孩子中较大的值交换            swap(arr, largestIndex, index);            //将索引指向孩子中较大的值的索引            index = largestIndex;            //重新计算交换之后的孩子的索引            left = 2 * index + 1;            right = 2 * index + 2;        }     }    //交换数组中两个元素的值    public static void swap(int[] arr, int i, int j) {        int temp = arr[i];        arr[i] = arr[j];        arr[j] = temp;    }

感谢各位的阅读,以上就是"c++怎么实现堆排序"的内容了,经过本文的学习后,相信大家对c++怎么实现堆排序这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

大根 结点 孩子 数组 索引 排序 结构 最大 最大值 位置 剩余 端的 保证 较大 小根 末尾 面的 顶端 c++ 数据 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 深圳汽车充电桩软件开发公司 成都网络安全行业集成商群 上海智能化网络技术开发产品 软件开发项目相关方案 广州新一代网络技术开发服务价格 设计数据库的步骤 街道网络安全领域 网络安全网络强国主题画 计算机通信网络技术课后习题 访问控制是网络安全 徐汇区数据软件开发质量保证 泛在网络技术的作用 中国保密协会成都网络安全 数据库utf8中文排序规则 软件开发目前比较缺的岗位 河北省网络安全测评机构 婚纱模板软件开发 软件开发费属于商品 机关开展网络安全工作存在的问题 学习电脑软件开发难吗 江西网络技术服务概况 怎么登录云服务器的秘钥 浙江安卓软件开发制作 软件开发不满意怎么退款 有关互联网科技的新闻客户端 怎么去学网络安全 qt 创建数据库表 中小学校园网络安全防范措施 LC3开源峰会网络技术系列 奉贤区通用软件开发服务产品介绍
0