持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天
选择排序
选择排序就是重复“从待排序的数据中寻找最小值,将其与序列最左边的数字进行交换”。在序列中寻找最小值时使用的是线性查找
图解
01
对数字1-9进行排序
02
使用线性查找在数据中寻找最小值,本题即1
03
将最小值1与序列最左边的6进行交换,最小值1归位。若最小值在最左端,则不需要任何操作
04
在剩下的数据中继续寻找最小值。即2
05
将2与左边第二个数字6交换,最小值2归位
06
重复操作直到都归位
07
排序完成
解说
选择排序使用了线性查找来寻找最小值,因此在第1轮中需要比较n-1个数字,第2轮需要比较n-2个数字……到第n-1轮的时候就只需比较1个数字了。因此,总的比较次数与冒泡排序的相同,都是(n-1)+(n-2)+…+1≈n²/2次。
每轮中交换数字的次数最多为1次。如果输入数据就是按从小到大的顺序排列的,便不需要进行任何交换。选择排序的时间复杂度也和冒泡排序的一样,都为O(n²)。
插入排序
插入排序是一种从序列左端开始依次对数据进行排序的算法。在排序过程中,左侧的数据陆续归位,而右侧留下的就是还未被排序的数据
01
对1-9排序
02
首先,假设最左边5已完成排序,此时只有5是已归位数字
03
接下来,从待排数字(未排序区域)中取出最左边的数字3,将它与左边已归位的数字进行比较。若左边的数字更大,就交换这两个数字。重复该操作,直到左边已归位的数字比取出的数字更小,或者取出的数字已经被移到整个序列的最左边为止。
04
5>3,故交换两数字
05
此时3.5归位
06
取未排序区域最左边的4,与左边的5进行比较
07
5>4,交换两数字,再把4和左边的3进行比较,3<4,操作结束
08
4归位
09
左边均比自己小时...
10
无需操作
11
重复操作,直到所有数字归位
12
排序完成
解说
在插入排序中,需要将取出的数据与其左边的数字进行比较。就跟前面讲的步骤一样,如果左边的数字更小,就不需要继续比较,本轮操作到此结束,自然也不需要交换数字的位置。
然而,如果取出的数字比左边已归位的数字都要小,就必须不停地比较大小,交换数字,直到它到达整个序列的最左边为止。具体来说,就是第k轮需要比较k-1次。因此,在最糟糕的情况下,第2轮需要操作1次,第3轮操作2次……第n轮操作n-1次,所以时间复杂度和冒泡排序的一样,都为O(n²)。
堆排序
堆排序的特点是利用了数据结构中的堆。之前关于堆的文章用的是顺序排列,此文用的是降序排列
01
首先,在堆中存储所有数据,按降序构建堆
02
<img src="p6-juejin.byteimg.com/tos-cn-i-k3…?" alt="2.jpg" width="30%"
为排序,从堆中把数据一个个取出来
提示:从降序排列的堆中取出数据时会从最大的数据开始取,所以将取出的数据反序输出,排序就完成了
03
首先取出根节点的数字7
04
重新构造堆
05
取出根节点数字6,放到从右数第二个位置
06
重新构造堆
07
重复操作直到堆变空为止
08
排序中......
09
从堆中取出所有数字,排序完成
解说
堆排序一开始需要将n个数据存进堆里,所需时间为O(nlogn)。排序过程中,堆从空堆的状态开始,逐渐被数据填满。由于堆的高度小于log₂n,所以插入1个数据所需要的时间为O(logn)。
堆排序的运行时间比之前讲到的冒泡排序、选择排序、插入排序的时间O(n²)都要短,但由于要使用堆这个相对复杂的数据结构,所以实现起来也较为困难。
补充说明
一般来说,需要排序的数据都存储在数组中。这次我们使用了堆这种数据结构,但实际上,这也相当于将堆嵌入到包含了序列的数组中,然后在数组中通过交换数据来进行排序。具体来说,就是让堆中的各结点和数组像下图这样呈对应关系。正如大家所见,这可以说是强行在数组中使用了堆结构。