数据结构从入门到精通——直接选择排序

直接选择排序

  • 前言
  • 一、选择排序的基本思想:
  • 二、直接选择排序
  • 三、直接选择排序的特性总结:
  • 四、直接选择排序的动画展示
  • 五、直接选择排序的代码展示
    • test.c
  • 六、直接选择排序的优化
    • test.c


前言

直接选择排序是一种简单的排序算法。它的工作原理是每一次从未排序部分选出最小(或最大)的一个元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。这种算法的时间复杂度为O(n^2),其中n是待排序元素的数量,因此在处理大数据集时效率较低。然而,它的实现简单,对于小规模的数据排序是一个不错的选择。


一、选择排序的基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

选择排序的基本思想是从未排序的序列中找到最小(或最大)的元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

这种排序算法的优点在于其实现过程相对简单,对于小规模的数据排序,其效率是可以接受的。然而,选择排序也存在明显的缺点。由于其每次都需要从未排序的元素中找到最小(或最大)的元素,这导致算法的时间复杂度为O(n^2),其中n为待排序元素的数量。这意味着当处理大规模数据时,选择排序的性能可能会变得非常低下。

在实际应用中,选择排序往往不是最优的选择,特别是对于大规模数据的排序。更高效的排序算法,如快速排序、归并排序、堆排序等,在处理大规模数据时,通常会有更好的性能表现。

但是,选择排序的思想在某些特定情境下仍然有其应用价值。例如,在某些需要稳定排序且数据量较小的场景中,选择排序可以作为一个简单且有效的解决方案。此外,选择排序的思想也可以作为其他更复杂排序算法的基础,帮助理解和学习更高级的排序算法。

总的来说,选择排序的基本思想虽然简单,但其性能上的局限性使得它在实际应用中并不常见。然而,这并不意味着它没有价值,通过深入理解和应用选择排序的思想,我们可以更好地理解排序算法的本质,并为学习更高级的排序算法打下坚实的基础。

二、直接选择排序

  • 在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  • 在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

直接选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

首先,我们假设有一个无序的整数列表,我们想要通过直接选择排序将其按升序排列。算法的工作流程可以分为以下几个步骤:

  1. 找到最小(大)元素:在列表中找到最小(大)的元素。这个步骤通常涉及遍历整个列表,比较每个元素的值。
  2. 交换位置:一旦找到最小(大)元素,将其与列表的第一个元素交换位置。这样,最小(大)的元素就被放到了它应该在的位置。
  3. 移除已排序元素:从列表中移除已排序的第一个元素(现在是最小(大)元素),然后对剩余的元素重复上述两个步骤。
  4. 重复过程:继续这个过程,每次从剩余的未排序元素中找到最小(大)元素,并将其与未排序部分的第一个元素交换。
  5. 结束条件:当整个列表都被排序时,算法结束。

直接选择排序的时间复杂度是O(n^2),其中n是列表的长度。这是因为它包含两个嵌套循环:一个用于找到最小(大)元素,另一个用于遍历整个列表。尽管这种排序方法在处理小型或中型列表时可能是有效的,但对于大型列表,更高效的排序算法(如快速排序、归并排序或堆排序)通常是更好的选择。

然而,直接选择排序有一个显著的优点,那就是它的实现相对简单,对于初学者来说是一个很好的学习工具。通过理解这个算法,可以对排序的基本概念有一个直观的认识,从而为学习更复杂的排序算法打下基础。

在实际应用中,直接选择排序可能不是最优选择,但它在教育、演示和教学方面仍然具有很高的价值。此外,对于某些特定类型的数据集(如部分有序的数据集),直接选择排序的性能可能会比其他算法更好。

三、直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

直接选择排序的特性总结起来,主要是其直观易懂、原地排序和不稳定排序的特点。

直接选择排序是一种简单直观的排序算法,其基本原理是每一次从未排序的部分选出最小(或最大)的一个元素,存放到排序序列的起始位置。它的操作过程是从左到右逐个选择剩余元素中的最小者,并将其与未排序部分的第一个元素交换。这种选择过程一直持续到未排序部分为空,排序也就完成了。因此,直接选择排序的直观性是其显著特点之一,使得初学者容易理解和实现。

另一个特性是原地排序,这意味着直接选择排序不需要额外的存储空间来进行排序,它直接在原始数组上进行操作,改变了原始数组的顺序。这一特性使得它在处理内存受限的场景时非常有用。

然而,直接选择排序也是一种不稳定的排序算法。稳定性是指如果两个元素的键值相等,那么在排序之后它们的相对位置不会改变。由于直接选择排序在每次选择最小(或最大)元素进行交换时,可能会改变相等元素的原始相对位置,因此它不具备稳定性。

总的来说,直接选择排序是一种简单直观、原地进行的排序算法,但它是不稳定的。在实际应用中,根据数据的特性和排序要求,可能需要选择更合适的排序算法。例如,对于大规模数据集,直接选择排序的效率可能较低,因为它需要多次遍历和交换操作。而对于小规模数据集或者对稳定性要求不高的场景,直接选择排序则是一个简单有效的选择。

四、直接选择排序的动画展示

直接选择排序是一种简单的排序算法。它通过每次从未排序部分选择最小(或最大)元素,与未排序部分的第一个元素交换位置,从而达到排序的目的。在动画展示中,可以看到每次选择的最小(或最大)元素逐步“冒泡”到已排序部分的末尾,直到整个序列有序。这种排序方法的时间复杂度为O(n^2),适用于小规模数据的排序。

选择排序

五、直接选择排序的代码展示

test.c

#include<stdio.h>
#include<stdlib.h>
#include<time.h>void SelectSort(int* a, int n);
void PrintArray(int* a, int n);
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void TestSelectSort()
{int a[] = { 5, 13, 9, 16, 12, 4, 7, 1, 28, 25, 3, 9, 6, 2, 4, 7, 1, 8 };//int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };PrintArray(a, sizeof(a) / sizeof(int));SelectSort(a, sizeof(a) / sizeof(int));PrintArray(a, sizeof(a) / sizeof(int));
}void PrintArray(int* a, int n)
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}
void TestOP()
{srand(time(0));const int N = 10000;int* a1 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; ++i){a1[i] = rand();}int begin1 = clock();SelectSort(a1, N);int end1 = clock();printf("SelectSort:%d\n", end1 - begin1);free(a1);
}
void SelectSort(int* a, int n)
{for (int k = 0; k < n; k++){int max = 0;for (int i = 0; i < n - k; i++){if (a[i] >= a[max])max = i;}Swap(&a[n - 1 - k], &a[max]);}}
int main()
{TestSelectSort();TestOP();return 0;
}

这段代码实现的是选择排序(Selection Sort)算法,而不是通常的冒泡排序(Bubble Sort)。选择排序是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

接下来我将逐步解释这段代码:

  1. 函数定义:
void SelectSort(int* a, int n)

这是一个名为 SelectSort 的函数,它接受一个整数数组 a 和一个整数 n 作为参数。n 是数组 a 的长度。

  1. 外层循环:for (int k = 0; k < n; k++)

这个循环从 0n-1 迭代,用于确定当前应该放置最小元素的位置。

  1. 初始化 max 变量:int max = 0;

在每次外层循环开始时,max 被初始化为 0。这个变量用于存储当前找到的最小元素的位置。

  1. 内层循环:for (int i = 0; i < n - k; i++)

这个循环从 0n-k-1 迭代。每次迭代,它都会检查从 a[0]a[n-k-1] 的元素,以找到当前最小元素的位置。

  1. 判断并更新最小元素的位置:if (a[i] >= a[max]) max = i;

这个条件检查 a[i] 是否大于或等于 a[max]。如果是,则更新 maxi。注意这里使用了 >= 而不是 >,这意味着如果有多个相同的最小元素,它们都会被正确地处理。

  1. 交换元素:Swap(&a[n - 1 - k], &a[max]);

在内层循环结束后,我们已经找到了从 a[0]a[n-k-1] 中的最小元素,它的位置是 max。现在,我们需要将这个最小元素与当前位置 n-1-k 的元素交换。

整体上,这段代码通过不断地选择并交换最小元素,最终将数组 a 排序为升序。

六、直接选择排序的优化

使用min和max对直接选择排序进行优化可以减少交换的次数。

在原始的直接选择排序算法中,每次迭代会通过查找最小值和最大值的索引来确定需要交换的元素。然后分别进行交换。这样可能会导致不必要的交换操作。

优化的思路是,在每次迭代中,同时查找最小值和最大值的索引,然后将它们记录下来,最后再进行一次交换操作。

具体实现如下:

void SelectSort(int* a, int n)
{int begin = 0, end = n - 1;while (begin < end){int min = begin, max = end;for (int i = begin; i <= end; i++){if (a[i] <= a[min]) min = i;if (a[i] >= a[max]) max = i;}// 将最小值放到已排序部分的起始位置Swap(&a[begin], &a[min]);// 如果最大值的索引是begin,将最大值的索引更新为minif (max == begin) max = min;// 将最大值放到已排序部分的末尾位置Swap(&a[end], &a[max]);begin++;end--;}
}

这样的优化可以减少交换的次数,提高排序的效率。同时,可以确保每次迭代只进行一次交换操作,减少了内存的读写次数,提高了算法的性能。

 if (max == begin) max = min;

关于这个代码是为了防止min正好在end,而max正好在begin这种的特殊情况

test.c

#include<stdio.h>
#include<stdlib.h>
#include<time.h>void SelectSort(int* a, int n);
void PrintArray(int* a, int n);
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void TestSelectSort()
{int a[] = { 5, 13, 9, 16, 12, 4, 7, 1, 28, 25, 3, 9, 6, 2, 4, 7, 1, 8 };//int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };PrintArray(a, sizeof(a) / sizeof(int));SelectSort(a, sizeof(a) / sizeof(int));PrintArray(a, sizeof(a) / sizeof(int));
}void PrintArray(int* a, int n)
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}
void TestOP()
{srand(time(0));const int N = 10000;int* a1 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; ++i){a1[i] = rand();}int begin1 = clock();SelectSort(a1, N);int end1 = clock();printf("SelectSort:%d\n", end1 - begin1);free(a1);
}
void SelectSort(int* a, int n)
{int begin = 0, end = n - 1;while (begin < end){int min = begin, max = end;for (int i = begin; i <= end; i++){if (a[i] <= a[min])min = i;if (a[i] >= a[max])max = i;}Swap(&a[begin], &a[min]);if (max == begin)max = min;Swap(&a[end], &a[max]);begin++;end--;}}
int main()
{TestSelectSort();TestOP();return 0;
}

这段代码实现的是选择排序算法,用于对数组a中的元素进行排序。传入参数是数组a和数组长度n

代码的主要思路是:通过每一次迭代,从未排序的元素中找到最小值和最大值,并将它们分别放到已排序部分的起始位置和末尾位置。然后缩小未排序部分的范围,再次进行迭代直至完成排序。

  1. 初始化变量begin为数组的起始索引0end为数组的终止索引n-1
  2. 进入循环,判断begin是否小于end。如果是,继续下面的操作;如果不是,说明排序已完成,退出循环。
  3. 在每一次迭代中,定义变量minmax,分别用于记录当前未排序部分的最小值和最大值的索引,初始值分别设为beginend
  4. beginend遍历数组a,找到当前最小值和最大值的索引,更新minmax
  5. 交换最小值和begin位置的元素,使当前最小值放到已排序部分的起始位置。
  6. 如果max等于begin,说明最大值原本就在begin位置,交换后已经移到了最小值应该在的位置,所以需要将max更新为min
  7. 交换最大值和end位置的元素,使当前最大值放到已排序部分的末尾位置。
  8. 完成一次迭代后,已排序部分的范围向两端缩小,begin增加1end减少1
  9. 重复2-8步骤,直到begin不小于end,排序完成。

总结起来,选择排序每次迭代都会确定未排序部分的最小值和最大值的位置,并将它们交换到已排序部分的起始和末尾位置。通过多次迭代,最终达到整个数组的有序状态。

在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop大数据应用:HDFS 集群节点缩容

目录 一、实验 1.环境 2.HDFS 集群节点缩容 二、问题 1.数据迁移有哪些状态 2.数据迁移失败 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xff08;已部署&#xff09; SecondaryNameNode &#xff08;已部署…

Epuck2机器人固件更新及IP查询

文章目录 前言一、下载固件更新软件包&#xff1a;二、查询机器人在局域网下的IP 前言 前面进行了多机器人编队仿真包括集中式和分布式&#xff0c;最近打算在实物机器人上跑一跑之前的编队算法。但由于Epuck2机器人长时间没使用&#xff0c;故对其进行固件的更新&#xff0c;…

直播预约丨《袋鼠云大数据实操指南》No.1:从理论到实践,离线开发全流程解析

近年来&#xff0c;新质生产力、数据要素及数据资产入表等新兴概念犹如一股强劲的浪潮&#xff0c;持续冲击并革新着企业数字化转型的观念视野&#xff0c;昭示着一个以数据为核心驱动力的新时代正稳步启幕。 面对这些引领经济转型的新兴概念&#xff0c;为了更好地服务于客户…

CTF题型 匿名函数考法例题总结

CTF题型 匿名函数考法&例题总结 文章目录 CTF题型 匿名函数考法&例题总结一 .原理分析二 .重点匿名函数利用1.create_function()如何实现create_function代码注入 2.array_map()3.call_user_func()4.call_user_func_array()5.array_filter() 三.例题讲解1.[Polar 靶场 …

详细分析Python模块中的雪花算法(附模板)

目录 前言1. 基本知识2. 模板3. Demo 前言 分布式ID的生成推荐阅读&#xff1a;分布式ID生成方法的超详细分析&#xff08;全&#xff09; 1. 基本知识 Snowflake 算法是一种用于生成全局唯一 ID 的分布式算法&#xff0c;最初由 Twitter 设计并开源 它被设计用于解决分布式…

【5G NB-IoT NTN】3GPP R17 NB-IoT NTN介绍

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

学生信息管理系统--修改信息(非常详细的修改,更新,撤销,删除逻辑)

目录 概述修改包括的操作修改在每个模块中的应用 详解修改与更新取消删除 特殊概念数据集游标 总结 概述 学生信息管理系统&#xff0c;功能相对简单且代码重复性高&#xff0c;应该采用复用的思想来减少代码的冗余和提高代码的可维护性。然而&#xff0c;对于基础入门项目来说…

wireshark数据捕获实验简述

Wireshark是一款开源的网络协议分析工具&#xff0c;它可以用于捕获和分析网络数据包。是一款很受欢迎的“网络显微镜”。 实验拓扑图&#xff1a; 实验基础配置&#xff1a; 服务器&#xff1a; ip:172.16.1.88 mask:255.255.255.0 r1: sys sysname r1 undo info enable in…

一文读懂!Mj AI作画是什么?5款Midjourney国内版软件必备!

mj ai 作画是什么&#xff1f; mj ai 作画&#xff0c;是 Midjourney ai 作画的缩写&#xff0c;这里的 Midjourney 是海外一款非常出名的 AI 绘画软件&#xff0c;其受欢迎程度和影响力之广&#xff0c;某种程度上让它成了 AI 作画的代名词&#xff0c;正如 ps 在平面设计领域…

D-Star 寻路算法

D-Star 寻路算法 下面简写 D-Star 为 D* D算法&#xff1a;D 算法”的名称源自 Dynamic A Star,最初由Anthony Stentz于“Optimal and Efficient Path Planning for Partially-Known Environments”中介绍。它是一种启发式的路径搜索算法&#xff0c; 适合面对周围环境未知或者…

静态代理IP测试:有何优点?

随着互联网的普及&#xff0c;越来越多的人开始使用动态IP进行上网。但是在某些情况下&#xff0c;我们可能需要使用静态IP进行测试或特定的网络设置。本文将介绍如何获取静态IP进行测试以及静态IP的优点。 一、如何获取静态IP进行测试&#xff1f; 1.联系ISP&#xff08;Int…

Docker Desktop 安装 ClickHouse 超级简单教程

Docker desktop 安装 clickhouse 超级简单 文章目录 Docker desktop 安装 clickhouse 超级简单 什么是 Docker &#xff1f;安装下准备安装Docker配置安装 ClickHouse配置数据库密码DBeaver 测试创建表总结 什么是 Docker &#xff1f; 下载 Docker desktop Docker Desktop …

红外相机和RGB相机标定:实现两种模态数据融合

1. 前期准备 RGB相机&#xff1a;森云智能SG2-IMX390&#xff0c;1个红外相机&#xff1a;艾睿光电IR-Pilot 640X-32G&#xff0c;1个红外标定板&#xff1a;https://item.taobao.com/item.htm?_ujp3fdd12b99&id644506141871&spma1z09.2.0.0.5f822e8dKrxxYI 2.操作步…

Spring MVC开发小练习

1. 加法计算器 需求&#xff1a;输入两个整数&#xff0c;计算和 约定前后端交互接口&#xff1a; 在开发项目前&#xff0c;根据需求先约定好前后端交互接口&#xff0c;双方按照接口文档进行开发&#xff0c;接口文档一旦写好&#xff0c;尽量不要轻易改变&#xff0c;如果…

CPU设计实战-Wishbone总线接口

为什么需要改用总线接口&#xff1f; 1.但是在实际应用中&#xff0c;程序的体积可能非常大&#xff0c;指令存储器就不能再集成在FPGA内部了&#xff0c;一般使用FPGA芯片外部的Flash作为指令存储器。同理,-般使用FPGA芯片外部的SDRAM作为数据存储器。 2.统一接口标准。 很多…

蓝桥杯 2023 省B 飞机降落

首先&#xff0c;这题要求的数据量比较少&#xff0c;我们可以考虑考虑暴力解法。 这题可能难在很多情况的考虑&#xff0c;比如说&#xff1a; 现在时间是10&#xff0c;有个飞机20才到&#xff0c;我们是可以干等10分钟。 #include <iostream> #include <…

0101插入排序-算法基础-算法导论第三版

文章目录 一 插入排序二 循环不变式与插入排序的正确性三 伪代码中的一些约定四 Java代码实现插入排序结语 一 插入排序 输入&#xff1a; n n n个数订单一个序列 ( a 1 , a 2 , ⋯ , a n ) (a_1,a_2,\cdots,a_n) (a1​,a2​,⋯,an​). **输出&#xff1a;**输入序列的一个排…

OpenWRT+zeroTier旁路由组网

前言 我之前写过一篇文章&#xff0c;探究了zeroTier的最基础的玩法&#xff0c;那篇文章结尾我提到了使用zeroTier虽然实现组网了&#xff0c;但是我只能访问局域网中制定的设备&#xff0c;局域网中其他设备无法访问&#xff0c;这篇文章我又研究了一套方案openwrtzeroTier旁…

IEEE Transactions on Medical Imaging(TMI)论文推荐:2024年01月(1)

Unsupervised Domain Adaptation for Medical Image Segmentation by Disentanglement Learning and Self-Training 摘要&#xff1a;无监督域适应(Unsupervised domain adaptive, UDA)旨在提高深度模型在无标记数据上的分割性能&#xff0c;近年来受到广泛关注。在本文中&…

el-input设置max、min无效的解决方案

目录 一、方式1&#xff1a;type“number” 二、方式2&#xff1a;oninput&#xff08;推荐&#xff09; 三、计算属性 如下表所示&#xff0c;下面为官方关于max&#xff0c;min的介绍&#xff1a; el-input&#xff1a; max原生属性&#xff0c;设置最大值min原生属性&a…