排序算法(归并排序法待补充)
要点概论:
1. 冒泡排序法
2. 选择排序法
3. 插入排序法
4. 快速排序法
5. 归并排序法
6. python 语言提供的排序算法
1. 冒泡排序法
冒泡排序法时最简单的排序算法。对于包含 N 个元素的列表 A ,按递增顺序排列的冒泡法的算法如下。
1)第一轮比较:从第一个元素开始,对列表中所有 N 个元素进行两两大小比较,如果不满足升序关系,则交换。
即 A[0] 与 A[1] 比较,若A[0] > A[1] , 则 A[0] 与 A[1] 交换;然后 A[1] 与 A[2] 比较,若A[1] > A[2] ,则 A[1] 与 A[2] 交换;
......直至最后 A[N -2] 与 A[N - 1] 比较, 若 A[N - 2] > A[N -1] ,则 A[N -2] 与 A[N - 1] 交换。
第一轮比较完成后,列表元素中最大的数 “沉” 到列表最后,而那些较小的数如同气泡一样上浮一个位置,顾名思义 “冒泡法” 排序
2)第二轮比较:从第一个元素开始,对列表中前 N - 1 个元素(第 N 个元素,即 A[N - 1]已经最大,无须参加排序)继续两两大小比较,如果不满足升序关系,则交换。
第二轮比较完成后,列表元素中次大的数 “沉” 到最后,即 A[N - 2] 为列表元素中次大的数。
3)以此类推,进行第 N - 1 轮比较后,列表中所有元素均按递增顺序排好序。
PS:若要按递减顺序对列表排序,则每次两两大小比较时,如果不满足降序关系,则交换即可。
冒泡排序法的过程如下表所示:
原始列表 | 2 | 97 | 86 | 64 | 50 | 80 | 3 | 71 | 8 | 76 |
第一轮比较 | 2 | 86 | 64 | 50 | 80 | 3 | 71 | 8 | 76 | 97 |
第二轮比较 | 2 | 64 | 50 | 80 | 3 | 71 | 8 | 76 | 86 | 97 |
第三轮比较 | 2 | 50 | 64 | 3 | 71 | 8 | 76 | 80 | 86 | 97 |
第四轮比较 | 2 | 50 | 3 | 64 | 8 | 71 | 76 | 80 | 86 | 97 |
第五轮比较 | 2 | 3 | 50 | 8 | 64 | 71 | 76 | 80 | 86 | 97 |
第六轮比较 | 2 | 3 | 8 | 50 | 64 | 71 | 76 | 80 | 86 | 97 |
第七轮比较 | 2 | 3 | 8 | 50 | 64 | 71 | 76 | 80 | 86 | 97 |
第八轮比较 | 2 | 3 | 8 | 50 | 64 | 71 | 76 | 80 | 86 | 97 |
第九轮比较 | 2 | 3 | 8 | 50 | 64 | 71 | 76 | 80 | 86 | 97 |
冒泡排序算法的主要时间消耗时比较次数。
当 i = 1 时,比较次数为 N - 1;当 i = 2 时,比较次数为 N - 2;依次类推。总共比较次数为:(N -1)+(N - 2)+ ...... + 2 + 1 = N(N -1)/ 2。
故冒泡排序法的时间复杂度为 O(N²).
冒泡排序算法的实现(bubbleSort.py):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def bubbleSort(a): for i in range(len(a)-1,-1,-1): # 外循环 for j in range(i): # 内循环 if a[j] > a[j + 1]: # 大数往下沉 a[j],a[j + 1] = a[j + 1],a[j] # print(a) # 跟踪调试 def main(): a = [2,97,86,64,50,80,3,71,8,76] bubbleSort(a) print(a) if __name__ == '__main__': main() # 程序运行结果如下: # [2, 3, 8, 50, 64, 71, 76, 80, 86, 97]
2. 选择排序法
对于包含 N 个元素的列表 A ,按递增顺序排序的选择法的基本思想是:每次在若干无序数据中查找最小数,并放在无序数据中的首位。其算法如下:
1)从 N 个元素的列表中找最小值及其下标,最小值与列表的第一个元素交换。
2)从列表的第二个元素开始的 N - 1 个元素中再找最小值及其下标,该最小值(即整个列表元素的次小值)与列表第二个元素交换。
3)以此类推,进行第 N - 1 轮选择和交换后,列表中所有元素均按递增顺序排好序。
PS:若要按递减顺序对列表排序,只要每次查找并交换最大值即可。
选择排序法的过程如下表所示:
原始数组 | 59 | 12 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 9 |
第一轮比较 | 9 | 12 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 59 |
第二轮比较 | 9 | 12 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 59 |
第三轮比较 | 9 | 12 | 31 | 64 | 72 | 69 | 46 | 89 | 77 | 59 |
第四轮比较 | 9 | 12 | 31 | 46 | 72 | 69 | 64 | 89 | 77 | 59 |
第五轮比较 | 9 | 12 | 31 | 46 | 59 | 69 | 64 | 89 | 77 | 72 |
第六轮比较 | 9 | 12 | 31 | 46 | 59 | 64 | 69 | 89 | 77 | 72 |
第七轮比较 | 9 | 12 | 31 | 46 | 59 | 64 | 69 | 89 | 77 | 72 |
第八轮比较 | 9 | 12 | 31 | 46 | 59 | 64 | 69 | 72 | 77 | 89 |
第九轮比较 | 9 | 12 | 31 | 46 | 59 | 64 | 69 | 72 | 77 | 89 |
选择排序算法的主要时间消耗时比较次数。
当 i = 1时,比较次数时 N - 1;当 i = 2 时,比较次数为 N - 2;以此类推。总共比较次数为:(N - 1)+(N - 2)+ ...... + 2 + 1 = N(N - 1)/ 2。
故选择排序算法的时间复杂度为 O(N²)。
选择排序算法的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def selectionSort(a): for i in range(0,len(a)): # 外循环 (0 ~ N-1) m = i # 当前位置下标 for j in range(i+1,len(a)): # 内循环 if a[j] < a[m]: # 查找最小值的位置 m = j a[i],a[m] = a[m],a[i] #元素交换 # print(a) # 跟踪调试 def main(): a = [59,12,77,64,72,69,46,89,31,9] selectionSort(a) print(a) if __name__ == '__main__': main() # 程序运行结果如下: # [9, 12, 31, 46, 59, 64, 69, 72, 77, 89]
3. 插入排序法
对于包含 N 个元素的列表 A ,按递增顺序排序的插入排序法的基本思想是:依次检查列表中的每个元素,将其插入到其左侧已经排好序的列表中的适当位置。其算法如下:
1)第二个元素与列表中其左侧的第一个元素比较,如果 A[0] > A[1] ,则交换位置,结果左侧两个元素排序完毕。
2)第三个元素依次与其左侧的列表的元素比较,直至插入对应的排序位置,结果左侧的三个元素排序完毕。
3)依次类推,进行第 N-1 轮比较和交换后,列表中所有元素均按递增顺序排好序。
PS:若要按递减顺序对列表排序,只要每次查找并交换最大值即可。
插入排序法的过程如下表所示:
原始数组 | 59 | 12 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 9 |
第一轮比较 | 12 | 59 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 9 |
第二轮比较 | 12 | 59 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 9 |
第三轮比较 | 12 | 59 | 64 | 77 | 72 | 69 | 46 | 89 | 31 | 9 |
第四轮比较 | 12 | 59 | 64 | 72 | 72 | 69 | 46 | 89 | 31 | 9 |
第五轮比较 | 12 | 59 | 64 | 69 | 72 | 77 | 46 | 89 | 31 | 9 |
第六轮比较 | 12 | 46 | 59 | 64 | 69 | 72 | 77 | 89 | 31 | 9 |
第七轮比较 | 12 | 46 | 59 | 64 | 69 | 72 | 77 | 89 | 31 | 9 |
第八轮比较 | 12 | 31 | 46 | 59 | 64 | 69 | 72 | 77 | 89 | 9 |
第九轮比较 | 9 | 12 | 31 | 46 | 59 | 64 | 69 | 72 | 77 | 89 |
在最理想的情况下(列表处于排序状态),while 循环仅需要一次比较,故总的运行时间为线性;
在最差的情况下(列表为逆序状态),此时内循环指令执行次数为: 1 + 2 + ...... +N - 1 = N(N - 1)/ 2 。
故插入排序算法的时间复杂度为 O(N²) 。
插入排序算法的实现(insertSort.py)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def insertSort(a): for i in range(1,len(a)): # 外循环 (1 ~ N-1) j = i print(j) # time.sleep(1) while (j > 0) and (a[j] < a[j - 1]): # 内循环 a[j],a[j - 1] = a[j - 1],a[j] # 元素交换 j -= 1 # 继续循环 print(j) # print(a) 跟踪调试 def main(): a = [59,12,77,64,72,69,46,89,31,9] insertSort(a) print(a) if __name__ == '__main__': main() # 程序运行结果如下: # [9, 12, 31, 46, 59, 64, 69, 72, 77, 89]
4. 快速排序法
快速排序法是对冒泡排序的一种改进,其基本思想是:
通关过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要小;然后递归对这两部分数据分别进行快速排序。
快速排序算法的一趟排序和操作步骤如下:
1)设置两个变量 i 和 j ,分别为列表首末元素的下标,即 i = 0 ,j = N - 1。
2)设置列表的第一个元素作为关键数据,即 key = A[0]。
3)从 j 开始向前搜索,找到第一个小于 key 的值 A[ j ] ,将 A[ j ] 和 A[ i ] 互换。
4)从 i 开始向后搜索,找到第一个大于 key 的值 A[ i ] ,将 A[ i ] 和 A[ j ] 互换。
5)重复第(3)和(4)步,直到 i = j 。
快速排序的一趟排序的算法如下表所示:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
原始数组 | 59 | 12 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 9 |
第一轮比较交换 | 9 | 12 | 77 | 64 | 72 | 69 | 46 | 89 | 31 | 59 |
第二轮比较交换 | 9 | 12 | 59 | 64 | 72 | 69 | 46 | 89 | 31 | 77 |
第三轮比较交换 | 9 | 12 | 31 | 64 | 72 | 69 | 46 | 89 | 59 | 77 |
第四轮比较交换 | 9 | 12 | 31 | 59 | 72 | 69 | 46 | 89 | 64 | 77 |
第五轮比较交换 | 9 | 12 | 31 | 46 | 72 | 69 | 59 | 89 | 64 | 77 |
第六轮比较交换 | 9 | 12 | 31 | 46 | 59 | 69 | 72 | 89 | 64 | 77 |
第七轮比较交换 | 9 | 12 | 31 | 46 | 59 | 69 | 72 | 89 | 64 | 77 |
快速排序最坏情况下,每次划分选取的基准都是当前无序列表中关键字最小(或最大)的记录,时间复杂度为 O(N²) ;
平均情况下,其时间复杂度为 O(Nlog2N) 。
快速排序算法的实现(quickSort.py)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def quickSort(a,low,high): # 对列表 a 快速排序,下界为 low ,上界为 high i = low # i 等于列表下界 j = high # j 等于列表上界 if i >= j: # 如果下界大于等于上界,法妞结果列表 a return a key = a[i] # 设置列表的第一个元素作为关键数据 # print(key) # 跟踪调试 while i < j: # 循环直到 i = j while i < j and a[j] >= key: # j 开始向前搜索,找到第一个小于 key 的值 a[j] j = j - 1 a[i] = a[j] while i < j and a[i] <= key: # i 开始向后搜索,找到第一个大于 key 的 a[i] i = i + 1 a[j] = a[i] a[i] = key # a[i] 等于关键数据 # print(a) # 跟踪调试 quickSort(a,low,i - 1) # 递归调用快速排序算法(列表下界为 low ,上界为 i - 1 ) quickSort(a,j + 1,high) # 递归调用快速排序算法(列表下界为 j + 1 ,上界为 high) def main(): a = [59,12,77,64,72,69,46,89,31,9] quickSort(a,0,len(a) - 1) print(a) if __name__ == '__main__': main() # 程序运行结果如下 # [9,12,31,46,59,64,69,72,77,89]
5. 归并排序法(待补充)
6. python 语言提供的排序算法
python 语言提供了下列排序算法:
1)内置数据类型 list 中的方法 sort() ,把列表的项按升序重新排列。
2)内置函数 sorted() 则保持原列表不变,函数返回一个新的包含按升序排列的项的列表。
python 系统排序方法使用了一种归并排序算法的版本,但使用了 python 无法编写的底层实现,从而避免了 python 本身附加的大量开销,故其速度比 mergeSort.py 快很多(10 ~ 20倍)。
系统排序方法同样用于任何可比较的数据类型,例如,python 内置的 str ,int 和 float 数据类型,