排序算法之堆排序_20230624

news/2024/5/19 6:08:29 标签: 排序算法, 算法, 数据结构, 堆排序

算法>排序算法堆排序

  1. 前言

堆排序是基于比较排序的一类算法算法重复利用堆(Binary heap)的特性,最大(最小)元素一定位于堆顶的位置,那么就可以提取堆顶元素,放置在数组的尾部位置,后再把剩余的元素进行堆处理,以此类推,最终完成排序任务。

  1. 堆定义

堆的定义如下,对于含有n个元素的序列
{ k 1 , k 2 , k 3 , . . . . , k n } \{k_1,k_2,k_3,....,k_n\} {k1,k2,k3,....,kn}
当且仅当满足下列关系时候,称之这个序列为堆(以大顶堆为例),

在这里插入图片描述

若将对应的此序列对应的一维数组看成是一个完全二叉树,则对的含义表明,完全二叉树中所有非终端节点的值均不小于其左、右孩子节点的值。由此,如果{k1,k2,…kn}是堆,则堆顶元素必为序列中n个元素的最大值。具体看一个例子,下面的完全二叉树则是一个大顶堆。值得一提的是,大顶堆中最小元素则可能位于任意叶子节点中,它并没有特别的规律。

在这里插入图片描述

在这里插入图片描述

上面两个大顶堆都是符合要求的合格大顶堆,大顶堆中最小元素值为9,它可能位于第④或第⑤或第⑥个位置上。所以在大顶堆中,并不能确认完全二叉树中的最小值所在确切位置。

若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素中的次小值。如此反复执行,便能得到一个有序序列,这个过程便称之为堆排序(heap sort)

  1. 堆排序过程

综上所述,堆排序过程分为几个过程:

  • 首先需要对输入的n无序元素进行大顶堆化处理
  • 交换堆顶元素和序列中的最后一个元素
  • 再对前n-1元素进行大顶堆化处理
  • 交换堆顶元素和序列中最后一个元素
  • 重复上述操作直至序列中仅剩一个元素(最小元素)

3-1 输入无序元素进行大顶堆化处理过程

给定数组元素arr={4,10,3,5,1},要求通过完全二叉树建立大顶堆,过程如下,

在这里插入图片描述

可以观察到,上面的完全二叉树为大顶堆,通过交换堆顶元素和最后一个元素的值,交换发生后,堆中的元素数量减1,并重新对堆中的元素大顶化处理。

在这里插入图片描述

在这里插入图片描述

最终排序结果arr={1,3,4,5,10}

在这里插入图片描述

  1. 堆排序实现

4-1 对调整函数的实现

已知H.r[s…m]中记录的关键字除H.r[s]之外的均满足堆的定义要求,本函数调整H.r[s]关键字,使H.r[s…m]成为一个大顶堆。

void heap_adjust(HeapType *heap, int s, int m)
{
    int j;
    RcdType rc;
    rc=heap->r[s];

    for(j=2*s;j<=m;j=j*2)
    {
        if(j<m && LT(heap->r[j].key,heap->r[j+1].key))
        {
            j++;
        }

        //if rc.key is less than heap->r[j].key(j is larger between two values)
        if(!LT(rc.key,heap->r[j].key))
        {
            break;
        }

        heap->r[s]=heap->r[j];
        s=j;
    }

    heap->r[s]=rc;

    return;
}

4-2 堆排序实现

void heap_sort(HeapType *heap)
{
    int i;
    int n;
    RcdType rc;

    n=heap->length;

    for(i=n/2;i>0;i--)
    {
        heap_adjust(heap,i,n);
    }

    for(i=n;i>1;i--) //if there is one left(>1) and it had been sorted
    {
        rc=heap->r[i];
        heap->r[i]=heap->r[1];
        heap->r[1]=rc;

        heap_adjust(heap, 1, i - 1);
    }

    return;
}

  1. 小结

堆排序对记录较小的序列并不提倡,但是对于较大n的文件还是很有效的。因为其运行时间主要消耗在初建堆和调整新建堆的反复筛选上。堆排序在最坏情况下的时间复杂度为O(nlgn)。相对快速排序而言,这是堆排序的最大优点。此外,堆排序仅需要一个记录大小供交换用的辅助空间。

参考资料

并不提倡,但是对于较大n的文件还是很有效的。因为其运行时间主要消耗在初建堆和调整新建堆的反复筛选上。堆排序在最坏情况下的时间复杂度为O(nlgn)。相对快速排序而言,这是堆排序的最大优点。此外,堆排序仅需要一个记录大小供交换用的辅助空间。

参考资料

  1. Heap Sort - Data Structures and Algorithms Tutorials - GeeksforGeeks

http://www.niftyadmin.cn/n/463348.html

相关文章

JDBC 望舒客栈项目 万字详解

目录 一、前言 二、项目结构 三、准备工作 1.建立子包 : 2.导入jar包 : 3.工具类 : 1 Utility工具类 2 JDBCUtilsDruid工具类 4.导入配置文件 : 5.引入BasicDAO : 四、项目主体 1.界面显示 : 1 代码演示 2 运行测试 2.用户登录 : 1 创建员工表employee 2 创建Ja…

CSS基础学习--24 表单

一、一个表单案例&#xff0c;我们使用 CSS 来渲染 HTML 的表单元素 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>CSS基础学习-表单</title> </head> <style> input[typetext], select {width:…

【C++学习】线程库 | IO流 | 空间配置器

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 一、线程库 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和平台相关的&#xff0c;比如w…

WMS中Choreographer 配合 VSYNC 中断信号

WMS中Choreographer 配合 VSYNC 中断信号 1、了解SurfaceFlinger中VSYNC信号刷新2、Choreographer 舞蹈编导2.1 Choreographer初始化2.2 FrameHandler中处理任务2.3 FrameDisplayEventReceiver初始化3.4 简易流程图 3、ViewRootImpl中scheduleTraversals3.1 postCallback 通过n…

EMQ的介绍及整合SpringBoot的使用

首先先了解一下底层的协议: 1. MQTT MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布/订阅 &#xff08;publish/subscribe&#xff09;模式的"轻量级"通讯协议&#xff0c;该协议构建…

React从入门到实战 -组件的三大核心属性(2)props

文章目录 基本使用对props进行限制类式组件中的构造器 基本使用 // 定义组件class MyComponent extends React.Component{render(){return (<ul><li>姓名&#xff1a;{this.props.name}</li><li>年龄&#xff1a;{this.props.age}</li><li>…

云原生入门指南:构建未来的弹性、高效和可靠应用

本文目录 第一部分&#xff1a;云原生概述第二部分&#xff1a;云原生技术栈第三部分&#xff1a;云原生应用开发实践云原生初体验结语&#xff1a; 第一部分&#xff1a;云原生概述 什么是云原生&#xff1f; 云原生的定义&#xff1a;云原生是一种构建和运行在云端的应用开发…

人工智能数据集处理——数据清理1

目录 一、概述 二、缺失值 1、检测缺失值 使用isna() 方法检测na_df中是否存在缺失值 使用natna() 方法 2、缺失值的处理 (1) 删除缺失值 使用删除dropna() 方法删除na_df 对象中缺失值所在的一行数据 删除全为缺失值的行 删除有缺失值的行 (2) 填充缺失值 使用fill…