数据结构七大排序算法图解——选择排序动图演示

系列文章目录

四、选择排序

紧接上一篇交换排序

前言:

1、直接选择排序

思想:

例题:

代码部分:

性能分析

2、树形选择排序

思想:

例题一:

例题二:

性能分析

3、堆排序

定义:

方法:

如何“筛选”?

例题:

如何“建初始堆”?

例题:

代码部分

性能分析

4、总结

直接选择排序

树形排序

堆排序


前言:

选择排序的主要思想是每一趟从待排序列中选取一个关键字值最小的记录,也即第 1 趟从 n 个记录中选取关键字值最小的记录,在第 2 趟中,从剩下的 n-1 个记录中选取关键字值最小的记录,直到整个序列中的记录都选完位置。这样,由选取记录的顺序便可得到按关键字值有序的序列。

1、直接选择排序

思想:

首先在所有记录中选出关键字值最小的记录,把它与第一个记录进行位置交换,然后在其余的记录中再选出关键字值次小的记录与第二个记录进行位置交换,依此类推,直到所有记录排好序。

此处引用网上一张比较经典的gif来展示直接选择排序的整个过程:

例题:

假设待排序的 8 个记录的关键字序列为 { 5,3,6,4,7,1,8,2} 排序过程如下图所示
红颜色为已排好序的数字,考试时一般用【中括号】代替

在这里插入图片描述

初始序列就把它看成无序序列

然后从无序序列中选择最小的跟这无序序列中第一个数交换,构成有序序列

第二趟也是从无序序列中选择最小的跟无序序列中第一个数交换

下面每一趟以此类推

每趟序列遍历完后,有序序列记录的个数 + 1,无序序列的个数 - 1,

代码部分:

public void selectSort(){ RecordNode temp; //定义一个零时变量temp for(int i=0; i<this.curlen-1;i++) //进行i-1次遍历,this.curlen:数组的长度 { int min=i; for(int j=i+1;j<this.curlen; j++) //找到一个最小的 if (r[j].key.compareTo(r[min].key)<0) min=j; if (min!=i) {temp=r[i]; //以下是交换代码 r[i]=r[min]; r[min]=temp;} } } 

性能分析

2、树形选择排序

思想:

  • 此处引用网上一张比较经典图来展示树形选择排序的整个过程:

先对 n 个记录进行俩俩比较,比较的结果是把关键字值较小者作为优胜者上升到父结点,得到比较的优胜者(关键字值较小者),作为第一步比较的结果保留下来;

然后对这个记录再进行关键字的两两比较,如此重复,直到选出一个关键字值最小的记录为止。

这个过程可用一个含有n个叶子结点的完全二叉树来表示

例题一:

对于由8个关键字组成的序列 { 52,39,67,95,70,8,25,¯52¯ },使用树形选择排序选出最小关键字值的过程可用下图所示的完全二叉树来表示。

在这里插入图片描述

可以看到关键字都处在最后一层的叶子节点上
怎么选呢?俩俩 PK ,谁小谁上去到父亲节点,52 和 39,39 上去;67 和 95,67 上去;70 和 8,8 上去;
到上一层同样也是谁小谁上去到父亲节点,最后关键字最小的在最上面

例题二:

同上图例题一,找次小值

在这里插入图片描述

在例题一中,最小的找到了,然后把他当做无穷大 “∞”,然后再俩俩 PK 就可以找到次小,次小的找到了再把它替换成无穷大,每次都找到这些当中最小的弄到父亲节点,以此类推,最后就排好序了

性能分析

3、堆排序

定义:


换一种说法就是:
所有的父亲结点都大于孩子结点的叫大顶堆
所有的父亲结点都小于孩子结点的叫小顶堆
不大不小的不叫堆

此处引用网上一张比较经典的图来展示大小顶堆:
        大顶堆中根节点的值一定是整个序列中最大的
        小顶堆中根节点的值一定是整个序列中最小的

所以,堆的含义表明:完全二叉树中所有非终端结点(父亲结点)的值均不大于(或不小于)其左、右孩子结点的值。

  • 此处引用网上一张比较经典的 gif来展示:

方法:

首先把待排序的记录序列对应成一棵完全二叉树,并把它转换成一个初始堆(即首先建初始堆)。这时,根结点具有最大(或最小)的关键字值,然后,交换根结点和最后一个结点(即第n个结点)的位置,除最后一个结点之外,前 n-1 个结点仍构成一棵完全二叉树,再把它们调整为一个堆。同样交换根结点和最后一个结点(即第 n-1 个结点)。重复进行下去,直到只剩下一个根结点为止,便得一个有序表。

如何“筛选”?

所谓 “ 筛选 ” 指的是调整的过程,对一棵左/右子树均为堆的完全二叉树,“ 调整 ” 根结点使整个二叉树也成为一个堆。

例题:

排序之前的关键字序列为
{ 40,55,49,73,12,27,98,81,64,36 }

下图中,方框内,棕色的为交换的,绿色的为不需要动的

“ 筛选 ” 是一个从上往下进行的过程。
可以看到每个父亲结点都比子节点大,所以是大顶堆

在这里插入图片描述

但是我们在排好序后最大值 98 应该放在最后面,下标为 9 的这个位置,但这样就需要把 12 挪上去,就是最大值需要跟最后一个结点的值进行交换

在这里插入图片描述

但在 98 和 12 进行互换之后,它就不是堆了,因此,需要对它进行 “ 筛选 ”,仍然把他调整成大顶堆
这时候需要从上到下筛选,但需要注意的是:因为已经找到最大值了,并且把他放在最后面,所以不需要再排最大值 98 了
先看 12、81、49,如果是大顶堆,需要把 81 放在最上面,81 和 12 交换

在这里插入图片描述

 但现在还不是大顶堆,接下来 73、12、36 比较,谁大谁上去,并交换,所以 73 和 12 交换

在这里插入图片描述

 然后 55 和 64 比较,谁大谁上去

在这里插入图片描述

这样的话又变成大顶堆了
根结点 81 最大,和无序序列的最后一个交换,这里是 12 。。。。。以此类推,每次筛选都能找到最大的,这样就排好序了

如何“建初始堆”?

如果建一个大顶堆,最顶上的根结点一定是最大的
如果建一个小顶堆,最顶上的根结点一定是最小的

例题:

建堆是一个从下往上进行 “ 筛选 ” 的过程。

例如:排序之前的关键字序列为
{ 40,55,49,73,12,27,98,81,64,36 }

在这里插入图片描述

先看下标 4 和 9,36 比 12 大,36 上去,
再看左边下标 3、7、8,81 比 73、64大,81 上去,
再看右边下标 2、5、6,98 比 27、49大,98 上去,

在这里插入图片描述

然后再来看下标 1、3、4,81 比 55、36大,81 上去,

在这里插入图片描述

但这样我们就发现一个问题:下标 3、7、8,这三个数(55、73、64)就不能构成大顶堆了
所以三个数比较后,73上去

在这里插入图片描述

然后看下标 0、1、2,98 比 81、40大,98 上去

在这里插入图片描述

但现在下标 2、5、6,这三个数(40、27、49)就不能构成大顶堆了
所以三个数比较后,49上去

在这里插入图片描述

现在,左/右子树都已经调整为堆,最后只要调整根结点,使整个二叉树是个 “ 堆 ” 即可。
这个就是建堆的过程,从下往上筛选(按照编号最大,并且有孩子的,此题中从 4 开始调整,然后 3、2、1),调整的过程中注意有可能打破子树上的堆,需要继续调。

代码部分

public class HeapSort { public static void heapSort(int[] arr) { if (arr == null || arr.length == 0) { return; } int len = arr.length; // 构建大顶堆,这里其实就是把待排序序列,变成一个大顶堆结构的数组 buildMaxHeap(arr, len); // 交换堆顶和当前末尾的节点,重置大顶堆 for (int i = len - 1; i > 0; i--) { swap(arr, 0, i); len--; heapify(arr, 0, len); } } private static void buildMaxHeap(int[] arr, int len) { // 从最后一个非叶节点开始向前遍历,调整节点性质,使之成为大顶堆 for (int i = (int)Math.floor(len / 2) - 1; i >= 0; i--) { heapify(arr, i, len); } } private static void heapify(int[] arr, int i, int len) { // 先根据堆性质,找出它左右节点的索引 int left = 2 * i + 1; int right = 2 * i + 2; // 默认当前节点(父节点)是最大值。 int largestIndex = i; if (left < len && arr[left] > arr[largestIndex]) { // 如果有左节点,并且左节点的值更大,更新最大值的索引 largestIndex = left; } if (right < len && arr[right] > arr[largestIndex]) { // 如果有右节点,并且右节点的值更大,更新最大值的索引 largestIndex = right; } if (largestIndex != i) { // 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换 swap(arr, i, largestIndex); // 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。 heapify(arr, largestIndex, len); } } private static void swap (int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } 

性能分析

4、总结

直接选择排序

首先在所有记录中选出关键字值最小的记录,把它与第一个记录进行位置交换,然后在其余的记录中再选出关键字值次小的记录与第二个记录进行位置交换,依此类推,直到所有记录排好序。

树形排序

先对 n 个记录进行俩俩比较,比较的结果是把关键字值较小者作为优胜者上升到父结点,得到比较的优胜者(关键字值较小者),作为第一步比较的结果保留下来;然后对这个记录再进行关键字的两两比较,如此重复,直到选出一个关键字值最小的记录为止。

堆排序

如果想要排升序,就应该建立大堆;
如果想要排降序;就应该建立小堆。

筛选就是被破坏后比较、交换。谁大谁上去,从上到下的顺序
建堆是一个从下往上进行 “ 筛选 ” 的过程。

Read more

Flutter 组件 bip340 适配鸿蒙 HarmonyOS 实战:次世代 Schnorr 签名,为鸿蒙 Web3 与隐私计算筑牢加密防线

Flutter 组件 bip340 适配鸿蒙 HarmonyOS 实战:次世代 Schnorr 签名,为鸿蒙 Web3 与隐私计算筑牢加密防线

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 bip340 适配鸿蒙 HarmonyOS 实战:次世代 Schnorr 签名,为鸿蒙 Web3 与隐私计算筑牢加密防线 前言 在鸿蒙(OpenHarmony)生态迈向去中心化金融(DeFi)、隐私通讯及安全资产管理等高阶安全场景的背景下,如何实现更高性能、更具扩展性且抗攻击能力的数字签名架构,已成为决定应用闭环安全性的“压舱石”。在鸿蒙设备这类强调分布式鉴权与芯片级安全(TEE/SE)的移动终端上,如果依然沿用传统的 ECDSA 签名算法,由于由于其固有的可延展性风险与高昂的聚合验证成本,极易由于由于在大规模节点验证时的 CPU 负载过高导致交互滞后。 我们需要一种能够实现签名线性聚合、计算逻辑极简且具备原生抗延展性的密码学方案。 bip340 为 Flutter 开发者引入了比特币 Taproot 升级的核心——Schnorr 签名算法。它不仅在安全性上超越了传统标准,更通过其线性的数学特性,

By Ne0inhk
(10-1)大模型时代的人形机器人感知:视觉-语言模型在机器人中的应用

(10-1)大模型时代的人形机器人感知:视觉-语言模型在机器人中的应用

本章内容聚焦大模型时代人形机器人的感知体系升级,系统介绍了视觉—语言模型、多模态Transformer与3D大模型在机器人中的核心作用,详细讲解了文本、视觉、点云与语音等信息的语义对齐与融合机制,介绍了从语言指令到视觉目标的Grounding、任务分解与意图理解方法,并通过闭环感知与决策联动,展示了大模型支撑机器人在复杂真实场景中的理解、规划与实时行动的用法。 10.1  视觉-语言模型在机器人中的应用 视觉—语言模型(Vision-Language Model,VLM)通过统一建模视觉与自然语言,使机器人具备“看懂并理解语言”的能力,是大模型时代机器人感知与认知融合的核心技术。VLM不仅能够完成图像识别、目标检测等传统感知任务,还可以直接理解语言指令、进行语义推理,并将高层语义映射为可执行的感知与行动目标,在人形机器人中广泛应用于交互理解、场景认知和任务执行等环节。 10.1.1  CLIP/BLIP/Flamingo等模型简介 随着大规模多模态数据与Transformer架构的发展,视觉—语言模型逐渐从“跨模态对齐”演进为“多模态理解与推理”。CLIP、BLIP与Flam

By Ne0inhk
Isaac Lab 机器人强化学习实战:配置架构、机器人添加流程与调参技巧全解析

Isaac Lab 机器人强化学习实战:配置架构、机器人添加流程与调参技巧全解析

0. 前言 Robot Lab 是基于 NVIDIA Isaac Lab 构建的机器人强化学习扩展库,专注于足式机器人的运动控制任务。该项目由 Ziqi Fan 开发维护,目前已支持包括 Unitree Go2、G1、H1 在内的十余款主流机器人平台。与原生 Isaac Lab 相比,Robot Lab 提供了更加完善的奖励函数库、域随机化配置以及针对不同机器人形态优化的训练参数。 在深入技术细节之前,有必要先理解 Isaac Lab 的基本架构。Isaac Lab 构建于 Isaac Sim 之上,采用分层设计:最底层是 Omniverse 渲染引擎与 PhysX 物理引擎,中间层是 Isaac Sim 提供的机器人仿真接口,最上层则是

By Ne0inhk
Flutter 组件 upnp_client 的鸿蒙适配实战 - 实现跨设备服务发现、智能家居自动关联与多媒体投屏协议控制

Flutter 组件 upnp_client 的鸿蒙适配实战 - 实现跨设备服务发现、智能家居自动关联与多媒体投屏协议控制

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 upnp_client 的鸿蒙适配实战 - 实现跨设备服务发现、智能家居自动关联与多媒体投屏协议控制 前言 在“万物互联”的愿景下,鸿蒙系统(OpenHarmony)最核心的武器就是跨设备协同能力。然而,如何让你的 Flutter 应用在复杂的家庭或办公内网中,自动发现并操控那些非鸿蒙生态但同样广泛分布的设备(如:DLNA 智能电视、家用路由器、网络打印机、甚至是 NAS 存储)? UPnP(Universal Plug and Play)协议此时扮演了全局搜索的关键角色。作为一套基于 SSDP 和 HTTP 处理发现与控制的老牌协议,它依然是局域网互联互通的“基础设施”。 upnp_client 为 Flutter

By Ne0inhk