数据结构:选择排序

简单选择排序

选择排序是一种简单直观的排序算法。首先在未排序序列中找到最大(最小)的元素,存放到排序学列的其实位置,然后在剩余的未排序的元素中寻找最小(最大)元素,存放在已排序序列的后面

算法步骤

  1. 在未排序序列中找到最大(小)元素,存放在排序序列的起始位置
  2. 再从剩余的未排序序列中找到最大(小)元素,然后存放在已排序序列的后面
  3. 重复上诉第二步骤,直至排序结束

算法理解

例如对无序表{56,12,80,91,20}采用简单选择排序算法进行排序,具体过程为:

  • 第一次遍历时,从下标为 1 的位置即 56 开始,找出关键字值最小的记录 12,同下标为 0 的关键字 56 交换位置:

    在这里插入图片描述

  • 第二次遍历时,从下标为 2 的位置即 56 开始,找出最小值 20,同下标为 2 的关键字 56 互换位置:

    在这里插入图片描述

  • 第三次遍历时,从下标为 3 的位置即 80 开始,找出最小值 56,同下标为 3 的关键字 80 互换位置:

    在这里插入图片描述

  • 第四次遍历时,从下标为 4 的位置即 91 开始,找出最小是 80,同下标为 4 的关键字 91 互换位置:

    在这里插入图片描述

  • 到此简单选择排序算法完成,无序表变为有序表。

代码实现

#include "iostream"
using namespace std;

#define MAX 9
//单个记录的结构体
typedef struct {
    int key;
}SqNote;
//记录表的结构体
typedef struct {
    SqNote r[MAX];
    int length;
}SqList;
//交换两个记录的位置
void swap(SqNote *a,SqNote *b){
    int key=a->key;
    a->key=b->key;
    b->key=key;
}
//查找表中关键字的最小值
int SelectMinKey(SqList *L,int i){
    int min=i;
    //从下标为 i+1 开始,一直遍历至最后一个关键字,找到最小值所在的位置
    while (i+1<L->length) {
        if (L->r[min].key>L->r[i+1].key) {
            min=i+1;
        }
        i++;
    }
    return min;
}
//简单选择排序算法实现函数
void SelectSort(SqList * L){
    for (int i=0; i<L->length; i++) {
        //查找第 i 的位置所要放置的最小值的位置
        int j=SelectMinKey(L,i);
        //如果 j 和 i 不相等,说明最小值不在下标为 i 的位置,需要交换
        if (i!=j) {
            swap(&(L->r[i]),&(L->r[j]));
        }
    }
}
int main() {
    SqList *L = new SqList;
    L->length=8;
    L->r[0].key=49;
    L->r[1].key=38;
    L->r[2].key=65;
    L->r[3].key=97;
    L->r[4].key=76;
    L->r[5].key=13;
    L->r[6].key=27;
    L->r[7].key=49;
    SelectSort(L);
    for (int i=0; i<L->length; i++) {
        cout << L->r[i].key << " ";
    }
    return 0;
}

代码实现

13 27 38 49 49 65 76 97

树形选择排序

树形选择排序(又称“锦标赛排序”),是一种按照锦标赛的思想进行选择排序的方法,即所有记录采取两两分组,筛选出较小(较大)的值;然后从筛选出的较小(较大)值中再两两分组选出更小(更大)值,依次类推,直到最后选出一个最小(最大)值。同样可以采用此方式筛选出次小(次大)值等

算法理解

整个排序的过程,可以用一棵具有 n 个叶子结点的完全二叉树表示。例如对无序表{49,38,65,97,76,13,27,49}采用树形选择的方式排序,过程如下:

  • 首先将无序表中的记录采用两两分组,筛选出各组中的较小值(如图 1 中的(a)过程);然后将筛选出的较小值两两分组,筛选出更小的值,以此类推(如图 1 中的(b)(c)过程),最终整棵树的根结点中的关键字即为最小关键字:

在这里插入图片描述

图 1 树形选择排序(一)

  • 筛选出关键字 13 之后,继续重复此方式找到剩余记录中的最小值,此时由于关键字 13 已经筛选完成,需要将关键字 13 改为“最大值”,继续重复此过程,如图 2 所示: 图 2 树形选择排序(二)

    在这里插入图片描述

通过不断地重复此过程,可依次筛选出从小到大的所有关键字。该算法的时间复杂度为O(nlogn),同简单选择排序相比,该算法减少了不同记录之间的比较次数,但是程序运行所需要的空间较多。

代码实现

#include "iostream"
using namespace std;
#define N 8
void TreeSelectionSort(int *mData)
{
    int MinValue = 0;
    int tree[N * 4]; // 树的大小
    int max, maxIndex, treeSize;
    int i, n = N, baseSize = 1;
    while (baseSize < n)
        baseSize *= 2;
    treeSize = baseSize * 2 - 1;
    for (i = 0; i < n; i++) {//将要排的数字填到树上
        tree[treeSize - i] = mData[i];
    }
    for (; i < baseSize; i++) {//其余的地方都填上最小值
        tree[treeSize - i] = MinValue;
    }
    // 构造一棵树,大的值向上构造
    for (i = treeSize; i > 1; i -= 2)
    {
        tree[i / 2] = (tree[i] > tree[i - 1] ? tree[i] : tree[i - 1]);
    }

    n -= 1;
    while (n != -1)
    {
        max = tree[1];        //树顶为最大值
        mData[n--] = max;     //从大到小倒着贴到原数组上
        maxIndex = treeSize;  //最大值下标
        while (tree[maxIndex] != max) {
            maxIndex--;
        }//找最大值下标
        tree[maxIndex] = MinValue;
        while (maxIndex > 1) {
            if (maxIndex % 2 == 0) {
                tree[maxIndex / 2] = (tree[maxIndex] > tree[maxIndex + 1] ? tree[maxIndex] : tree[maxIndex + 1]);
            }
            else {
                tree[maxIndex / 2] = (tree[maxIndex] > tree[maxIndex - 1] ? tree[maxIndex] : tree[maxIndex - 1]);
            }
            maxIndex /= 2;
        }
    }
}
int main()
{
    int a[N] = {49,38,65,97,76,13,27,49};
    TreeSelectionSort(a);
    for (int i = 0; i < N; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

运行结果

13 27 38 49 49 65 76 97

堆排序

堆排序 ( H e a p s o r t ) (Heapsort) (Heapsort)是指利用堆来实现的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。堆排序的平均时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

在这里插入图片描述

算法思想

了解了堆的基本性质之后,我们就可以看堆排序的基本思想。

  1. 将未排序的序列构造成大(或者小)顶堆,根据堆的性质我们可以找到序列中的最大(或者最小)值
  2. 把堆首和堆尾互换,并把堆的大小减 1 1 1
  3. 重复上面的步骤,直到堆的大小为 1 1 1

在这里插入图片描述

在这里插入图片描述

代码实现

#include "iostream"
using namespace std;
#define MAX 9
//单个记录的结构体
typedef struct {
    int key;
}SqNote;
//记录表的结构体
typedef struct {
    SqNote r[MAX];
    int length;
}SqList;
//将以 r[s]为根结点的子树构成堆,堆中每个根结点的值都比其孩子结点的值大
void HeapAdjust(SqList * H,int s,int m){
    SqNote rc=H->r[s];//先对操作位置上的结点数据进行保存,放置后序移动元素丢失。
    //对于第 s 个结点,筛选一直到叶子结点结束
    for (int j=2*s; j<=m; j*=2) {
        //找到值最大的孩子结点
        if (j+1<m && (H->r[j].key<H->r[j+1].key)) {
            j++;
        }
        //如果当前结点比最大的孩子结点的值还大,则不需要对此结点进行筛选,直接略过
        if (!(rc.key<H->r[j].key)) {
            break;
        }
        //如果当前结点的值比孩子结点中最大的值小,则将最大的值移至该结点,由于 rc 记录着该结点的值,所以该结点的值不会丢失
        H->r[s]=H->r[j];
        s=j;//s相当于指针的作用,指向其孩子结点,继续进行筛选
    }
    H->r[s]=rc;//最终需将rc的值添加到正确的位置
}
//交换两个记录的位置
void swap(SqNote *a,SqNote *b){
    int key=a->key;
    a->key=b->key;
    b->key=key;
}
void HeapSort(SqList *H){
    //构建堆的过程
    for (int i=H->length/2; i>0; i--) {
        //对于有孩子结点的根结点进行筛选
        HeapAdjust(H, i, H->length);
    }
    //通过不断地筛选出最大值,同时不断地进行筛选剩余元素
    for (int i=H->length; i>1; i--) {
        //交换过程,即为将选出的最大值进行保存大表的最后,同时用最后位置上的元素进行替换,为下一次筛选做准备
        swap(&(H->r[1]), &(H->r[i]));
        //进行筛选次最大值的工作
        HeapAdjust(H, 1, i-1);
    }
}

int main() {
    SqList *L = new SqList ;
    L->length=8;
    L->r[1].key=49;
    L->r[2].key=38;
    L->r[3].key=65;
    L->r[4].key=97;
    L->r[5].key=76;
    L->r[6].key=13;
    L->r[7].key=27;
    L->r[8].key=49;
    HeapSort(L);
    for (int i=1; i<=L->length; i++) {
        cout << L->r[i].key << " ";
    }
    return 0;
}

运行结果

13 27 38 49 49 65 76 97

注意:堆排序相对于树形选择排序,其只需要一个用于记录交换(rc)的辅助存储空间,比树形选择排序的运行空间更小。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/72135.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NLP文本分类

NLP文本分类 落地实战五大利器&#xff01;_kaiyuan_sjtu的博客-CSDN博客https://zhuanlan.zhihu.com/p/432619164 https://github.com/alibaba/EasyNLP/blob/master/README.cn.md

【5G 核心网】5G 多PDU会话锚点技术介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Docker部署rabbitmq遇到的问题 Stats in management UI are disabled on this node

1. Stats in management UI are disabled on this node #进入rabbitmq容器 docker exec -it {rabbitmq容器名称或者id} /bin/bash#进入容器后&#xff0c;cd到以下路径 cd /etc/rabbitmq/conf.d/#修改 management_agent.disable_metrics_collector false echo management_age…

什么是gRPC?

1. GRPC是google开源的rpc框架 2. 核心是一个.proto的服务描述文件 3. 添加依赖的grpc相关的包&#xff0c;配置IDEA的grpc插件&#xff0c;就可以很方便的生成调用代码 4. 通过在IDEA的protobuf插件上分别执行以下两个服务&#xff0c;就可以生成需要的调用代码 1&#xff…

2023深圳杯A题完整代码模型

已更新深圳杯A题全部版本&#xff0c;文末获取&#xff01; 摘要 现代社会&#xff0c;随着生活方式的变化和工作压力的增大&#xff0c;慢性非传染性疾病日益成为威胁公众健康的主要问题。心脑血管疾病、糖尿病、恶性肿瘤及慢性阻塞性肺病等慢性病的发病率呈现出上升趋势。为…

通过将信号频谱与噪声频谱进行比较,自动检测适当的带通滤波器转折频率研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

普通人怎样拥抱AI时代?这几点最为重要!

一、拒绝还是接受&#xff1f; 当纽约公立学校严禁学生用ChatGPT写论文之后&#xff0c;沃顿商学院的教授Ethan Mollick却开始鼓励自己的学生用ChatGPT来写论文。 图源于网络 试想一下&#xff0c;当所有学生都可以用ChatGPT写论文&#xff0c;大家的分数会有明显差别吗?一定…

Go把Map转成对象

最近使用了Redis的Hash&#xff0c;把一个对象给存储到了hash里面&#xff0c;具体如下&#xff1a; 现在需要从RedisHash缓存里面把结果给取出来&#xff0c;同时赋值到一个对象上面 result, err : global.GVA_REDIS.HGetAll(context.Background(), key).Result() 问题是resul…

基于STM32CUBEMX驱动TMOS模块STHS34PF80(1)----获取ID

基于STM32CUBEMX驱动TMOS模块STHS34PF80----1.获取ID 概述样品申请视频教程所有功能接口最小系统图生成STM32CUBEMX串口配置IIC配置IO口设置串口重定向 模块地址参考demoIIC写函数IIC读函数参考程序初始化获取ID主函数 概述 STHS34PF80 是一款非冷却、工厂校准的红外运动和存在…

Exploiting Proximity-Aware Tasks for Embodied Social Navigation 论文阅读

论文信息 题目&#xff1a;Exploiting Proximity-Aware Tasks for Embodied Social Navigation 作者&#xff1a;Enrico Cancelli&#xff0c; Tommaso Campari 来源&#xff1a;arXiv 时间&#xff1a;2023 Abstract 学习如何在封闭且空间受限的室内环境中在人类之间导航&a…

【JavaEE】懒人的福音-MyBatis框架—[单表]增删改查等常规操作

【JavaEE】MyBatis框架要点总结&#xff08;2&#xff09; 文章目录 【JavaEE】MyBatis框架要点总结&#xff08;2&#xff09;1. 单表查看操作1.1 (条件查询)通过id查找用户1.1.1 接口上声明方法1.1.2 xml文件中去实现方法1.1.3 测试 1.2 传递参数的重点问题&#xff1a;sql注…

监控Elasticsearch的关键指标

Elasticsearch 的核心职能就是对外提供搜索服务&#xff0c;所以搜索请求的吞吐和延迟是非常关键的&#xff0c;搜索是靠底层的索引实现的&#xff0c;所以索引的性能指标也非常关键&#xff0c;Elasticsearch 由一个或多个节点组成集群&#xff0c;集群自身是否健康也是需要我…

虚拟机的创建与使用

一、虚拟机的下载 链接&#xff1a;百度网盘下载链接 提取码&#xff1a;a9p4 二、新建虚拟机系统 需要有版本序列号 注意: 选择 第一个是纯dos 的窗口指令 桌面没有任何东西 选择第二个就是正常的操作系统.有文件夹 我的电脑之类的 三、从主机中复制文件到虚拟机中需要安装 …

阿里云服务器搭建Magento电子商务网站图文教程

本文阿里云百科分享使用阿里云服务器手动搭建Magento电子商务网站全流程&#xff0c;Magento是一款开源电商网站框架&#xff0c;其丰富的模块化架构体系及拓展功能可为大中型站点提供解决方案。Magento使用PHP开发&#xff0c;支持版本范围从PHP 5.6到PHP 7.1&#xff0c;并使…

如何通过CSS选择器选择一个元素的子元素?如何选择第一个子元素和最后一个子元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 选择一个元素的子元素⭐ 选择第一个子元素和最后一个子元素⭐ 注意事项⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

spark 图计算 助力解决 dataframe中的链式依赖

链式依赖说明 name newName a b c d b c 我们需要的结果 即我们可以支持获取到链式转换的 起点 重点 以及链式的中间转换过程顺序数组. 特别说明: 出版只支持 单向 无分叉的图,其他复杂场景暂时未测试. 场景举例: 比如某件商品价格变化,我们需要知…

gitee(码云)如何生成并添加公钥配置用户信息

一&#xff0c;简介 在使用Gitee的时候&#xff0c;公钥是必须的&#xff0c;无论是克隆还是上传。本文主要介绍如何本地生成和添加公钥到服务器&#xff0c;然后配置自己的用户信息&#xff0c;方便日后拉取与上传代码。 二&#xff0c;步骤介绍 2.1 本地生成公钥 打开git ba…

接口测试之Jmeter+Ant+Jenkins接口自动化测试平台

平台简介 一个完整的接口自动化测试平台需要支持接口的自动执行&#xff0c;自动生成测试报告&#xff0c;以及持续集成。Jmeter支持接口的测试&#xff0c;Ant支持自动构建&#xff0c;而Jenkins支持持续集成&#xff0c;所以三者组合在一起可以构成一个功能完善的接口自动化…

CDN(Content Delivery Network)内容分发网络

从DNS域名系统到CDN内容分发网络 DNS什么是DNS直接使用DNS的缺点 CDNCDN加速过程使用CDN的优势 DNS 什么是DNS 输入域名www.baidu.com后&#xff0c;浏览器先检查缓存和本地Host文件&#xff0c;看有没有对应的ip地址&#xff0c;有则直接使用&#xff0c;没有就会向本地DNS服…

Shader 编程:三角形、矩形等多边形绘制

该原创文章首发于微信公众号&#xff1a;字节流动 未经作者&#xff08;微信ID&#xff1a;Byte-Flow&#xff09;允许&#xff0c;禁止转载 SDF 有向距离场 上节其实牵扯到 SDF 算法&#xff0c;因为后面涉及高级特效的时候会经常用到&#xff0c;这里先提前对它做个简单的介…