排序算法 —— 堆排序

server/2024/10/22 8:26:55/

目录

1.堆排序的思想

2.堆排序的实现

建堆

向上调整建堆

向下调整建堆

选数

堆排序实现代码

3.堆排序总结


1.堆排序的思想

堆排序是利用堆这种数据结构设计的算法>排序算法,更准确的说,是利用堆的删除操作所设计的一种算法>排序算法

比如:删除堆顶元素的时候,我们使用的是替换法删除,也就是将堆顶元素和数组末尾的元素交换,每次选择的堆顶元素是堆中当前的最大or最小元素。相当于每次都能在待排序序列中选出一个最值,从后往前填入数组中的一个正确位置。

  • 如果是大堆,每次选出的数据就是当前堆中最大的元素,从数组后面往前填入数组,排出来的数据是升序的。
  • 如果是小堆,每次选出的数据就是当前堆中最小的元素,从数组后面往前填入数组,排出来的数据是降序的。

所以,如果我们想排升序,建堆的时候,应该建立大堆;如果我们想排降序,建堆的时候,应该建立小堆

2.堆排序的实现

堆排序的实现主要分为两步:建堆选数。

建堆

堆排序是在堆这种数据结构的基础上进行的,所以想要进行堆排序必须先建堆。建堆方式分为两种,一种是向上调整建堆,一种是向下调整建堆。

向上调整建堆

向上调整前提是当前调整的数据 前面的数据构成堆。所以,向上调整建堆的顺序应该从上往下、从左往右依次进行向上调整。一个数据通过向上调整建堆最多调整树的高度减1次,也就是logN,一共N个数据,所以向上调整建堆的时间复杂度是O(N*logN)

向下调整建堆

向下调整前提是左右子树都是堆,也就是当前数据后面的数据是堆。所以,向下调整建堆的顺序应该从右往左、从下往上依次进行。因为,叶子结点没有孩子,所以应该从倒数第一个非叶子结点开始进行向下调整

向下调整建堆代码:

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;}}
}

向下调整建堆时间复杂度分析:

向下调整建堆的时间复杂度为O(N),要优于向上调整建堆,所以我们采用向下调整建堆。 

选数

所谓选数,就是每次都选择堆顶元素,然后将堆顶元素和数组未排序空间的最后一个元素交换,每次选择的堆顶元素是堆中当前的最大or最小元素。相当于每次都能在待排序序列中选出一个最值,从后往前填入数组中的一个正确位置。

流程图如下所示:

堆排序实现代码

#include <stdio.h>void swap(int* p1, int *p2)
{int t = *p1;*p1 = *p2;*p2 = t;
}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)
{// 向下调整建堆// O(N)for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}int main()
{int nums[] = {5,4,8,9,6,3,2,1,7,0};HeapSort(nums,10);int i = 0;while(i < sizeof(nums) / sizeof(int)){printf("%d ",nums[i]);i++;}return 0;
}

3.堆排序总结

  • 时间复杂度:O(N*logN)。采用向下调整建堆,时间复杂度为O(N);逐元素进行向下调整,时间复杂度为log(N);所以总的时间复杂度为O(N*logN)。
  • 空间复杂度:O(1)。并没有开辟额外的空间,时间复杂度为O(1)。
  • 稳定性:不稳定,如图所示。


http://www.ppmy.cn/server/133847.html

相关文章

基于Springboot新能源汽车租赁管理系统JAVA|VUE|SSM计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

SpringSecurity 整合 JWT

前言 前后端分离项目中&#xff0c;如果直接把 API 接口对外开放&#xff0c;我们知道这样风险是很大的&#xff0c;所以引入了 Spring Security &#xff0c;但是我们在登陆后缺少了请求凭证部分。 什么是JWT? JWT是 Json Web Token 的缩写。它是基于 RFC 7519 标准定义的…

衡石分析平台系统分析人员手册-仪表盘控件概述

控件​ 控件是仪表盘的基本组成单位。控件种类很多&#xff0c;有展示分析数据的图表类类控件&#xff0c;有展示图片、文字的展示类控件&#xff0c;还有可导出数据、刷新数据、过滤数据等功能类控件。一个完整的仪表盘由多种不同功能的控件构成。 控件类型​ 根据控件是否展…

数据结构与算法--返回袋子数

去商店买苹果&#xff0c;商店只提供两种类型的袋子&#xff0c;只能装下6个苹果的袋子和只能装下8个苹果的袋子。买的苹果&#xff0c;必须用袋子装满&#xff0c;如果装不满&#xff0c;则不买。 给定一个正整数&#xff0c;返回至少使用多少个袋子。 public class Code_Appl…

MySQL-30.索引-介绍

一.索引 为什么需要索引&#xff1f;当我们没有建立索引时&#xff0c;要在一张数据量极其庞大的表中查询表里的某一个值&#xff0c;会非常的消耗时间。以一个6000000数据量的表为例&#xff0c;查询一条记录的时间耗时约为13s&#xff0c;这是因为要查询符合某个值的数据&am…

【JavaScript】Javascript基础Day01:let/const变量、数据类型、ES6模板字符串

Javascript——Day01 01. Javascript简介和体验02. Javascript书写位置03. Javascript注释和结束符04. Js输入和输出语句和字面量05. 变量的声明和赋值06. 变量的更新以及输入用户名案例07. 交换两个变量案例08. 变量的本质和命名规则09. var和let区别10. 数组的基本使用11. 常…

3. IoC 与DI

一、 定义 IoC&#xff0c;即控制反转&#xff0c;把对象的调用权交给容器&#xff0c;通过容器来实现对象的装配和管理。DI&#xff0c;即依赖注入&#xff0c;对象之间依赖关系由容器在运行期决定&#xff0c;由容器动态的将依赖关系注入到对象之中。DI&#xff0c;是对IoC更…

鸿蒙开发超好用的 UI 组件和工具类库 BasicLibrary

大家好&#xff0c;我是 V 哥。你在学习HarmonyOS NEXT 开发吗&#xff0c;今天 V 哥给你推荐一款超好用的三方库BasicLibrary&#xff0c;BasicLibrary 是一个基于 API 11 封装的基本库&#xff0c;旨在提升鸿蒙开发效率。它包含了一些常用的 UI 组件和实用工具类&#xff0c;…