首页 > 编程语言 >扎实打牢数据结构算法根基,从此不怕算法面试系列之010 week02 01-01 最简单的排序算法-选择排序法的设计思想

扎实打牢数据结构算法根基,从此不怕算法面试系列之010 week02 01-01 最简单的排序算法-选择排序法的设计思想

时间:2023-04-21 23:15:04浏览次数:51  
标签:arr 01 元素 最小 算法 数组 排序

1、基础排序算法

接下类,我们学习另外一类非常基础的算法,即排序算法。
排序算法是计算机科学领域研究的非常深入的一类算法,排序这个动作本身也是非常重要的,
很多时候面对无需的数据,首先需要做的就是对他们进行排序。


排序算法——目的:让数据有序。
排序算法——种类:种类也非常多,适用于不同的情景。
排序算法——思想:蕴含着重要的计算机科学中的算法设计思想。


我们即将学习2个简单的排序算法

  • 1、选择排序法
  • 2、插入排序法

通过对这2个基础的排序算法的学习,引申出更多东西,以打牢算法基础;
后续学习更加高级和更加复杂的算法时,可以有充分的准备。

特别是插入排序法,由于它的一些特殊性质,后续我们甚至在一些高级排序算法的学习中,甚至需要用到这种
类似插入排序这样的低级算法来进行一些优化。


2、选择排序法算法设计思想

我们接下来首先来看选择排序法。什么是选择排序法呢?它的思路本身很简单。
比如说,给我们一些待排序的元素,我们如何将这些本来是乱序的元素从小到大排列好呢?
非常简单,思路如下;

先在所有元素中将最小的元素拿出来
剩下的元素中,把最小的拿出来
剩下的元素中,把最小的拿出来
剩下的元素中,把最小的拿出来
……
只剩下一个元素,这个元素就是“剩下的元素中”最小的元素,将这最后一个元素拿出来

即:每次都选择还没处理的元素中最小的元素。
上述的思路就是选择排序法

我们现在创建一个数组如下:
mark

其中最小的元素是1:
mark
拿出最小的元素1:
mark
接着继续拿出最小的元素,分别拿出2、3、4:
mark
直到所有“剩余的最小的元素”全部拿完,新的排序后数组出现:
mark

我们上述的图片流程,我们的数组从6、3、2、1、5、4
到1、2、3、4、5、6的这个过程。

其实是使用了一个额外的数组空间,是从旧的数组6、3、2、1、5、4的基础上,新开辟了一个数组。
之后每次从旧的数组中找到剩下的元素中最小的元素,然后存储到新开辟的数组中……

这样一个过程,其实这样操作就占用了额外的空间,也是一种空间上的浪费。

接下来,我们要做的一个比较重要的事情是,我们的选择排序可否在原地完成
这也是排序算法中非常重要的一个概念,即原地排序

可以参考度娘的定义:原地排序


后续,我们会接触较多原地排序的算法,随着深入学习,我们会发现,有些算法可以用原地排序的方式实现;
但是对于另外一些排序算法,我们是无法原地排序实现的,必须借助额外的空间。

我们今天即将实现的选择排序就是一个可以原地排序的算法。

接下来,我们对选择排序进行图流程讲解。


我们直接实现原地排序的算法代码,
其实思路比较简单,我们每一轮找剩下的元素中最小的元素,我们只需要把我们找到的最小的元素直接放在数组开头的位置即可,即直接利用原来的数组空间即可。
举一个例子:
对于我们的数组的索引i,它初始的时候指着我们的数组索引为0的位置,表示我们现在想寻找排序之后的数组的第0个元素的位置应该是谁?

mark

为了找到这个最小的元素,我们可以再增加一个索引j,这个索引j从索引为0的位置出发,扫描一遍所有的元素,找到其中最小的元素。
之后我们再使用一个minIndex索引,记录索引j找到的最小的元素所在的索引位置。

mark

增加一个索引j,这个索引j从索引为0的位置出发,扫描一遍所有的元素:
j从0开始扫描:
mark

j扫描结束:
mark

j找到的最小的元素所在的索引位置,记为minIndex:
mark

排序之后的数组,它所对应的元素,应该是此时minIndex指向的1这个元素,现在i这个位置指向的元素是6这个元素,
我们所要做的事情,只需要把1和6这两个元素交换位置,此时i=0这个位置的元素就已经是最小的那个元素了。
交换前:
mark
交换后:
mark

接下来,进一步,我们就可以做i=1的操作:
mark

我们再做这一步的时候,我们就可以看到,每一步开始前,相当于arr[i……n)是未排序的(注意arr[i……n)是前闭后开)。
顺便提一句:这里的分析,用到了我们之前梳理过的循环不变量的知识。
循环不变量

从arr[1]到arr[n]都还没有排序,但是arr[0]已经排序好了。


arr[i……n)是未排序的(注意arr[i……n)是前闭后开);
arr[i……n)中的最小值要放到arr[i]的位置;而原本arr[i]位置的元素,我们放到数组后面去,在后续的循环中继续处理。即min(arr[i]……arr[n])与arr[i]做交换。

j从arr[i]出发:
mark
j扫描完整个数组:
mark
j扫描完整个数组后,找到最小元素的索引,记作minIndex:
mark
arr[i]与arr[minIndex]做交换:
交换前:
mark

交换后:
mark

此时arr[0]、arr[1]都已经排好序了。
下一轮循环开始前:
mark

mark
之后和前两轮循环一样,走完所有循环……
最后一轮循环过程如下:
j从arr[i]开始扫描:
mark
j扫描完整个数组:
mark
j扫描完整个数组后,找到最小元素的索引,记作minIndex:
mark
arr[i]与arr[minIndex]做交换:
交换前:
mark
交换后:
mark

至此,整个数组重新排序完成。
整个流程的关键是什么呢?

1、arr[i……n)未排序,arr[0……i)已排序;
2、arr[i……n]中的最小值要放到arr[i]的位置。

其中的1,1、arr[i……n)未排序,arr[0……i)已排序;(注,这个就是我们我们的选择排序法的循环不变量)
循环不变量

我们每一轮循环都在保持这个循环不变量,我们保持的方法就是2:
2、arr[i……n]中的最小值要放到arr[i]的位置。

这样,我们就原地完成了选择排序法

标签:arr,01,元素,最小,算法,数组,排序
From: https://www.cnblogs.com/xlfcjx/p/17342128.html

相关文章

  • 冒泡排序
    1,问题描述:对N个整数(数据由键盘输入)进行升序排列。2.问题分析:对于N个数因其类型相同,我们可利用数组进行存储。冒泡排序是在两个相邻元素之间进行比较交换的过程将一个无序表变成有序表。冒泡排序的思想:首先,从表头开始往后扫描数组,在扫描过程中逐对比较相邻两个元素的大小。若相......
  • 06 基础查询-单表01
    06基础查询-单表01数据库既然是存储数据的,那么做数据的检索就是必不可少了。查询数据操作是数据库中使用频率最高的操作,学习方案是:单表查询子查询连接查询组合查询SQL执行顺序查询SQL在解析的时候的先后顺序如下:fromjoinonwheregroupby(开始使用select中的别名,后......
  • 08 基础查询-单表02:分组和排序
    08基础查询-单表02:分组和排序Groupby分组SQL聚集函数可用来汇总数据。这使我们能够对行进行计数,计算和与平均数,获得最大和最小值而不用检索所有数据。目前为止的所有计算都是在表的所有数据或匹配特定的WHERE子句的数据上进行的。比如:SELECTemp.empid,emp.ename,emp.sex,em......
  • 查找算法
    查找算法1.线性查找线性查找(OrderSearch)是最简单的一种查找算法,直接从头到尾遍历,直至找到要查找的值为止。1.1代码实现packagecom.algorithm;/***@authorSnkrGao*@create2023-04-2019:52*/publicclassOrderSearch{publicstaticvoidmain(String[]......
  • 从原理聊JVM(一):染色标记和垃圾回收算法
    作者:京东科技 康志兴1JVM运行时内存划分1.1运行时数据区域•方法区属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。运行时常量池,属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用。JDK1.8之前,Hotspot虚拟机对方法区......
  • 算法学习day01数组part02-209、59、977
    packageLeetCode.arraypart02;/***209.长度最小的子数组*给定一个含有n个正整数的数组和一个正整数target。*找出该数组中满足其和≥target的长度最小的连续子数组[numsl,numsl+1,...,numsr-1,numsr],并返回其长度。如果不存在符合条件的子数组,返回0.*......
  • linux 中实现数据的每一行进行排序
     001、(base)[b20223040323@admin1test2]$lsa.txt(base)[b20223040323@admin1test2]$cata.txt##测试数目689375256882427(base)[b20223040323@admin1test2]$foriin{1..3};dosed-n"$i"pa.txt|sed's//\n/g'|......
  • 快速幂算法——求a^b % p的一种快速方法
    先想暴力怎么求解可以循环b次,每次从而求出a^b%p,时间复杂度为O(b),而这里的b是很大的,达到了2*10^9数量级,所以这么做会TLE1#include<iostream>2usingnamespacestd;3intmain(){4inta,b,p;5longlongres=1;6cin>>a>>b>>p;7......
  • 堆排序
    1.堆的定义: 在一颗完全二叉树中,每一个根节点的值均大于(或小于)其左右子树根节点的值,被称为堆。堆分为两种类型:大根堆和小根堆。其中每一棵子树的根节点的值大于等于左右子树节点的值,被称大根堆。如果是每个节点的值均小于等于左右节点的值,被称为小根堆。......
  • 基础算法-快速排序
    思路快速排序是一种常见的排序算法,它的基本思路是通过分治的方法将一个大的问题分解成小的问题进行解决。具体而言,快速排序的核心思路是选取一个枢轴元素,将序列分为两个子序列,其中一个子序列的所有元素都比枢轴元素小,而另一个子序列的所有元素都比枢轴元素大,然后对这两个子序列分......