【排序算法】——选择排序

前言

        排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列。所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作

        排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。

简介

        所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序。这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后的数据便于筛选和计算,大大提高了计算效率。对于一个排序算法的优劣,我们需要从它的时间复杂度、空间复杂度和稳定性三个方面来考虑。什么叫稳定性呢?即当两个相同的元素同时出现于某个序列之中,则经过一定的排序算法之后,两者在排序前后的相对位置不发生变化。换言之,即便是两个完全相同的元素,它们在排序过程中也是各有区别的。

        本篇文章讲述的是排序算法中的选择排序,其中包含了两种排序算法,分别是直接选择排序堆排序,下面将会一一为大家详细介绍。(用升序进行讲解)

      

基本思想

         选择排序算法的基本思想是为每一个位置选择当前最小的元素。

 1.直接选择排序 

        下面我们首先来看一看直接选择排序算法的动图演示:

        看了上图我们可以得知,直接选择排序算法是首先从第1个位置开始对全部元素进行选择,选出全部元素中最小的给该位置,再对第2个位置进行选择,在剩余元素中选择最小的给该位置即可;以此类推,重复进行“最小元素”的选择,直至完成第(n-1)个位置的元素选择,则第n个位置就只剩唯一的最大元素,此时不需再进行选择。 

        直接选择排序算法的思路以及代码都比较简单,有了上述讲解相信大家都已经对其了解了。

 2.堆排序

        直接选择排序是选择排序的一种,但是其时间复杂度很高,在实际应用中效率非常低下,那有没有其他的效率高的选择排序呢?答案当然是有的,那就是堆排序(Heapsort),堆排序主要借助了我们的数据结构--堆来实现。(若是对堆不了解的可以去阅读我的另一篇文章数据结构--堆)。

        当一个堆是大根堆的时候我们知道堆顶元素永远是整个堆中最大的元素,因此每次取堆顶我们都会得到一个最大值(降序则需要用小根堆),这刚好与我们选择排序算法的基本思想相同。下面我将同图画来给大家进行演示:

        此时堆顶元素是数组中最大的元素,将其与最后一个元素交换位置,并对堆进行调整。

       此时对于 9 这个元素我们可以理解为已经把它从该堆中删除了,此时堆中只剩下4个元素,重复此操作即可完成排序,大家可以根据下方的代码具体了解。

代码实现

 1.直接插入排序

        先看原始代码:

void Select_sort(vector<int>& a)
{
    int n = a.size();
    //对于直接选择排序来说,只需要进行n - 1次循环即可
    for (int i = 0; i < n - 1; i++)
    {
        int minpos = i;
        //从i位置开始,遍历其后面的数组,找到最小值
        for (int j = i + 1; j < n; j++)
        {
            if (a[j] < a[minpos])
            {
                minpos = j;
            }
        }
        //将最小值所处的位置与i位置的值进行交换即可
        swap(a[i], a[minpos]);
    }
}

        解析:两次循环即可完成,第一层循环控制需要排序的位置,第二次循环寻找该位置后的最小值。

        对于直接选择排序,我们有一种优化办法,可以使其的时间效率增加一倍,虽说时间复杂度是相同的,杯水车薪,但也是一种思路。 

具体思路:

        第一层循环我们从数组的两端开始遍历;

        第二次循环我们同时寻找其中间的最大值和最小值。

        代码如下:

void Select_sort(vector<int>& a)
{
    int n = a.size();
    //数组大小为奇数,最后会处于left == right;当数组大小为偶数时,最后会处于left > right
    //因此结束条件为left < right
    for (int left = 0, right = n - 1; left < right; left++, right--)
    {
        int minpos = left;
        int maxpos = left;
        //从left位置遍历其后面到right位置之前的数组,找到最小值和最大值
        for (int i = left + 1; i < right; i++)
        {
            if (a[i] < a[minpos])
            {
                minpos = i;
            }
            if (a[i] > a[maxpos])
            {
                maxpos = i;
            }
        }
        //此时在交换元素时需要注意一个细节:
        //当我们将a[right]与a[maxpos]交换时,maxpos位置上之前可能是left的位置,这样在之后的交换会出现问题,因此我们需要进行判断接下来的交换是否还要进行
        swap(a[right], a[maxpos]);
        if (a[minpos] < a[left])
        {
            swap(a[left], a[minpos]);
        }
    }
}

         对于优化后的直接选择排序在最后的交换步骤时的细节需要大家额外注意,大家可以自己用一个倒序数组亲自体验一下,以便有更深刻的体会。

 2.堆排序 

        先看代码:

//向下调整算法
void AdjustDown(vector<int>& a, int parent, int end)
{
    int child = parent * 2 + 1;
    while (child < end)
    {
        if (child + 1 < end && a[child] < a[child + 1])
        {
            child++;
        }

        if (a[child] > a[parent])
        {
            swap(a[child], a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

void Heap_sort(vector<int>& a)
{
    int n = a.size();
    //首先进行建堆
    for (int i = (n - 1 - 1) / 2; i >= 0; i--)
    {
        AdjustDown(a, i, n);
    }

    //进行排序
    for (int i = n - 1; i > 0; i--)
    {
        swap(a[0], a[i]);
        AdjustDown(a, 0, i);
    }
}

        对于堆排序来说,比较重要的地方是当我们在进行排序时,一定要注意当每一次交换完元素后,堆中的数据就会减少一个,因此当我们在自己写向下调整算法时,一定要注意此时堆中的数据个数,不然就会出现错误。 

        注:对于建堆和向下调整算法不了解的朋友可以先去看一看数据结构--堆,里面有较为详细的介绍。

总结

1.时空复杂度

        经过分析我们可以得到直接选择排序的时间复杂度和空间复杂度,两层for循环以及常数个变量,因此

直接选择排序:

        时间复杂度:O(N ^ 2)

        空间复杂度:O(1)

        对于堆排序来说,时间复杂度由建堆操作和排序操作决定,具体的计算过程较为复杂,感兴趣的可以自己搜索一下,这里不再赘述。因此

堆排序:

        时间复杂度:O(NlogN)

        空间复杂度:O(1)

        堆排序算法的总体时间复杂度是 O(n log n),这是因为建堆之后,还需要进行 n-1 次的排序操作,每次排序操作的时间复杂度是 O(log n)。但是,建堆本身的时间复杂度是线性的,这使得堆排序在某些情况下比其他 O(n log n) 排序算法更高效。 

2.稳定性

        在排序算法中,我们不光要关注算法的时空复杂度,还在看看算法的稳定性,什么是稳定性呢?

稳定性是假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

        简单分析我们可以知道选择排序算法是不稳定的。举例说明:序列58539.我们知道第一遍选择第1个元素“5”会和元素“3”交换,那么原序列中的两个相同元素“5”之间的前后相对顺序就发生了改变。因此,我们说选择排序不是稳定的排序算法,它在计算过程中会破坏稳定性。(对于直接选择排序以及堆排序都是如此)

直接选择排序: 不稳定

堆排序:            不稳定

尾声

        若有纰漏或不足之处欢迎大家在评论区留言或者私信,同时也欢迎各位一起探讨学习。感谢您的观看!

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

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

相关文章

递归实现指数型枚举(递归)

92. 递归实现指数型枚举 - AcWing题库 每个数有选和不选两种情况 我们把每个数看成每层&#xff0c;可以画出一个递归搜索树 叶子节点就是我们的答案 很容易写出每dfs函数 dfs传入一个u表示层数 当层数大于我们n时&#xff0c;去判断每个数字的选择情况&#xff0c;输出被选…

无限次使用 cursor pro

github地址 cursor-vip 使用方式 在 MacOS/Linux 中&#xff0c;请打开终端&#xff1b; 在 Windows 中&#xff0c;请打开 Git Bash。 然后执行以下命令来安装&#xff1a; 部分电脑可能会误报毒&#xff0c;需要关闭杀毒软件/电脑管家/安全防护再进行 方式1&#xff1a;通过…

【AI热点】小型语言模型(SLM)的崛起:如何在AI时代中找到你的“左膀右臂”?

人工智能模型的演变 多年来&#xff0c;谷歌等科技巨头和OpenAI等初创公司&#xff0c;一直在不遗余力地利用海量在线数据&#xff0c;打造更大、更昂贵的人工智能&#xff08;AI&#xff09;模型。这些大型语言模型&#xff08;LLM&#xff09;被广泛应用于ChatGPT等聊天机器…

解决Nginx + Vue.js (ruoyi-vue) 单页应用(SPA) 404问题的指南

问题描述 在使用Vue.js构建的单页应用&#xff08;SPA&#xff09;中&#xff0c;特别是像ruoyi-vue这样的框架&#xff0c;如果启用了HTML5历史记录模式进行路由管理&#xff0c;那么用户直接访问子路径或刷新页面时可能会遇到404错误。这是因为当用户尝试访问一个非根路径时…

Ubuntu22.04配置3D gaussian splatting

这篇博客提供了3D gaussian splatting在新安装Ubuntu上的配置过程。 1.拉仓库 2.安装显卡驱动和cuda版本 3.安装Pytorch 4.安装Pycharm和配置Python 5.安装附加依赖项&#xff08;方法一&#xff09; 6.安装Anaconda&#xff08;方法二&#xff09; 7.测试 1.拉仓库 # HT…

在 Visual Studio Code 中编译、调试和执行 Makefile 工程 llama2.c

在 Visual Studio Code 中编译、调试和执行 Makefile 工程 llama2.c 1. Installing the extension (在 Visual Studio Code 中安装插件)1.1. Extensions for Visual Studio Code1.2. C/C1.2.1. Pre-requisites 1.3. Makefile Tools 2. Configuring your project (配置项目)2.1.…

深度解析:推荐系统的进化之路与深度学习革命

目录 前深度学习时代一推荐系统的进化之路 浪潮之巅一深度学习在推荐系统中的应用 Embedding 技术在推荐系统中的应用 Embedding的原理 Embedding的分类 Word2vec Item2vec Embedding 与深度学习推荐系统的结合 YouTube 推荐系统召回层 局部敏感哈希 多角度审视推…

MAPTR:在线矢量化高精地图构建的结构化建模与学习(2208)

MAPTR: STRUCTURED MODELING AND LEARNING FOR ONLINE VECTORIZED HD MAP CONSTRUCTION MAPTR&#xff1a;在线矢量化高精地图构建的结构化建模与学习 ABSTRACT High-definition (HD) map provides abundant and precise environmental information of the driving scene, se…

SpringBoot集成Canal实现MySQL实时同步数据到Redis

MySQL增量数据同步利器Canal环境搭建流程 软件环境 JDK17.0.12 canal-server1.1.7 canal-client1.1.7 MySQL5.7 IDEA2024.2.0.2 我们先看Canal1.1.7源码对应的项目结构 1、基于源码编译打包 # 源码下载地址 https://github.com/alibaba/canal # 执行以下命令&#xff0…

嵌入式驱动开发详解16(音频驱动开发)

文章目录 前言WM8960简介I2S协议接口说明 SAI音频接口简介驱动框架简介设备树配置内核使能声卡设置与测试 后续参考文献 前言 该专栏主要是讲解嵌入式相关的驱动开发&#xff0c;但是由于ALSA驱动框架过于复杂&#xff0c;实现音频编解码芯片的驱动不是一个人能完成的&#xf…

OpenGL ES 03 加载3张图片并做混合处理

OpenGL ES 02 加载3张图片并做混合处理 什么是纹理单元纹理单元的作用使用纹理单元的步骤详细解释加载图片并绑定到到GPU纹理单元采样器的设置1.设置采样器变量的纹理单元编号&#xff0c;目的是为了告诉纹理采样器&#xff0c;从哪个纹理单元采集数据2.如果你没有显式地设置采…

JAVA没有搞头了吗?

前言 今年的Java程序员群体似乎承受着前所未有的焦虑。投递简历无人问津&#xff0c;难得的面试机会也难以把握&#xff0c;即便成功入职&#xff0c;也往往难以长久。于是&#xff0c;不少程序员感叹&#xff1a;互联网的寒冬似乎又一次卷土重来&#xff0c;环境如此恶劣&…

短视频矩阵贴牌:打造品牌新势力的策略与实践

在数字化浪潮席卷全球的今天&#xff0c;短视频以其独特的魅力迅速崛起&#xff0c;成为连接用户与品牌的重要桥梁。企业为了快速抢占市场&#xff0c;提升品牌影响力&#xff0c;纷纷探索短视频矩阵贴牌这一新兴模式。本文将深入探讨短视频矩阵贴牌的概念、优势、实施流程及注…

视频生成Sora的全面解析:从AI绘画、ViT到ViViT、TECO、DiT、VDT、NaViT等

前言 真没想到&#xff0c;距离视频生成上一轮的集中爆发(详见《Sora之前的视频生成发展史&#xff1a;从Gen2、Emu Video到PixelDance、SVD、Pika 1.0》)才过去三个月&#xff0c;没想OpenAI一出手&#xff0c;该领域又直接变天了 自打2.16日OpenAI发布sora以来(其开发团队包…

简易记事本项目(基于Vue 3 + Element Plus + SSM 个人事件管理系统)

项目简介 点滴365是一个基于 Vue 3 Element Plus SSM 开发的个人事件管理系统,旨在帮助用户高效管理 个人日程 和 待办事项。系统支持日记撰写、待办事项管理、数据统计分析、图片上传、定时提醒、实时天气等功能,让用户可以更好地记录生活点滴、规划工作任务。 核心技术栈…

【C语言】头文件

所有学习过C语言的朋友都熟悉这样一段代码&#xff1a; #include <stdio.h>int main(int argc, char *argv[]) {return 0; }那么&#xff0c;你真的了解 <stdio.h> 吗&#xff1f; <stdio…

ChatGPT Search开放:实时多模态搜索新体验

点击访问 chatTools 免费体验GPT最新模型&#xff0c;包括o1推理模型、GPT4o、Claude、Gemini等模型&#xff01; ChatGPT Search&#xff1a;功能亮点解析 本次更新的ChatGPT Search带来了多项令人瞩目的功能&#xff0c;使其在搜索引擎市场中更具竞争力。 1. 高级语音模式&…

概率论得学习和整理31: 连续型随机变量的概率本质是求面积,均匀分布等

目录 1 连续性随机变量 2 连续性随机变量和 离散型随机变量&#xff0c;分布的区别 3 不要混淆概念 4 均匀分布的相关 4.1 定义 4.2 例子 1 连续性随机变量 连续性随机变量最大的特点&#xff0c;单个点上的概率0多了一个分布函数&#xff0c;因为从1维变2维了&#xff…

跟沐神学读论文-论文阅读管理

摘要 近期有读论文的需求&#xff0c;就需要去了解一下论文到底要怎么读&#xff0c;同一个系列之间的论文如何作整理和归纳&#xff0c;之前也有了解过市面上有成熟的论文阅读工具&#xff0c;但是对于学生党来讲没什么性价比&#xff0c;在B站上看到沐神有讲解他的思路Typor…

java_断点调试(debug)

按照如下配置好后&#xff0c;即可点击“F7”,进入相应的方法&#xff0c;查看源码 package com.hspedu.debug_;//debug对象创建的过程&#xff0c;加深对调试的理解 public class Debug01 {public static void main(String[] args) {//创建对象的流程//&#xff08;1&#xff…