搜索与排序—— 冒泡排序选择排序插入排序与希尔排序

Posted 鲸骑

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搜索与排序—— 冒泡排序选择排序插入排序与希尔排序相关的知识,希望对你有一定的参考价值。

搜索与排序(三)—— 冒泡排序、选择排序、插入排序与希尔排序

本节开始,我们开始学习排序。排序可以对使某些算法从中受益,如之前讲过的二分法,就是建立在排好序的集合上的。
本节所演示的排序均为从小到大排序。

冒泡排序

冒泡排序可以说是排序中的经典了,虽然通常是被认为最低效的排序方法。。。但是还是得掌握一下。之所以称之为冒泡法,因为其原理是从第一项开始,将该项与剩下的项相比,小(大)则交换位置,这样逐个遍历集合中的项,每一轮遍历最小(大)的项将会被交换到顶部,犹如冒泡一般。

代码

1def bubbleSort(alist):
2    for i in range(len(alist)-1):
3        for j in range(i+1,len(alist)):
4            if alist[j]<alist[i]:
5                alist[i], alist[j] = alist[j], alist[i]

复杂度

O(n^2)

选择排序

选择排序改进了冒泡排序,每轮遍历找出最大值所在位序,结束该轮循环后再进行一次交换。

代码

1def selectionSort(alist):
2    for i in range(len(alist)-1,0,-1):
3        positionOfMax = i
4        for j in range(0, i):
5            if alist[j] > alist[positionOfMax]:
6                positionOfMax = j
7        alist[positionOfMax], alist[i] = alist[i], alist[positionOfMax]

复杂度

选择排序与冒泡排序有着数量相同的比较次数,复杂度也为O(n^2)。不过由于交换次数的减少,选择排序在实际中效率更高。

插入排序

插入排序始终在集合较低位置维持一个排序的子集合,然后再将每个新项“插回”原来的子列表。

在对某项进行操作之前,其前面的项已经为排好序的子列表(我们从集合的第二项开始,这样第一个元素即为单个元素的子列表),我们只需要将该项A与前子列表从后往前各个项B逐项比较,小则将B往后移一位。这样每轮比较后,将该插入原子列表中的“空位”。

代码

 1def insertSort(alist):
2    for index in range(1, len(alist)):
3        currentvalue = alist[index]
4        position = index
5
6        while position > 0 and alist[position-1] > currentvalue:
7            alist[position] = alist[position-1]
8            position -= 1
9
10        alist[position] = currentvalue

复杂度

插入排序的最大比较次数是 n-1 个整数的总和。同样,是 O(n^2 )。然而,在最好的情况下,
每次通过只需要进行一次比较。这是已经排序的列表的情况。

关于移位和交换的一个注意事项也很重要。通常,移位操作只需要交换大约三分之一的处理
工作,因为仅执行一次分配。在基准研究中,插入排序有非常好的性能。

希尔排序

希尔排序通过将原始列表分解为多个较小的子列表来进行插入排序。选择这些子列表的方式是希尔排序的关键。

希尔排序分解子列表并不为连续的,而是采用增量(gap)等距构造子列表。

本节采用的增量为,第一轮为n/2,第二轮为n/4…直至增量变为1.

代码

 1def shellSort(alist):
2    sublistcount = len(alist) // 2
3    while sublistcount > 0:
4        for startposition in range(sublistcount):
5            gapInsertionSort(alist, startposition, sublistcount)
6
7        sublistcount = sublistcount // 2
8
9def gapInsertionSort(alist, start, gap):
10    for index in range(start+gap, len(alist), gap):
11
12        currentvalue = alist[index]
13        position = index
14
15        while position >= gap and alist[position-gap] > currentvalue:
16            alist[position] = alist[position-gap]
17            position -= gap
18
19        alist[position] = currentvalue

复杂度

看起来似乎希尔排序不会比插入排序更好,因为其最后一轮都对整个集合执行了完整的插入排序,再加上前几轮的插入排序, 执行的操作似乎更多。但实际上,每一轮遍历都会产生比前一个“更有序”的列表,这使得下一轮的遍历非常高效。

对希尔排序的分析远远超出了本文的范围,我们可以说,它倾向于落在 O(n)和O(n^2 ) 之间的某处。


end

以上是关于搜索与排序—— 冒泡排序选择排序插入排序与希尔排序的主要内容,如果未能解决你的问题,请参考以下文章

八大基础排序中(直接插入排序,希尔排序,冒泡排序, 快速排序,归并排序,简单选择排序)

数据结构与算法 4:排序算法,选择/插入/冒泡/希尔/快速/归并

用简单的思维理解选择插入冒泡和希尔排序

排序算法学习(直接插入排序,希尔排序,选择排序,堆排序,冒泡排序)

插入排序与希尔排序算法

Java八股文面试题 基础篇 -- 二分查找算法冒泡排序选择排序插入排序希尔排序快速排序