排序算法总结1 #
- python内置函数排序实现
- 排序算法的分类
- 排序算法的稳定性
收获 #
学完本节内容,可以对排序算法有更全面的了解。
python内置函数排序实现 #
python中,有一个自带的内置函数,可以实现排序,其调用形式为:
list=[1,5,3,2] list.sort() print(list) 或者 list_new=sorted(list) print(list_new)
其实现的内部机制为Timesort,其最坏时间复杂度为O(n log n),空间复杂度为O(n)
排序算法的分类 #
排序算法大致可分为两类,非线性时间比较类排序和线性时间非比较类排序。其中,非线性时间比较类排序又可以分为交换类,插入类,选择类排序和归并排序。如下图所示。
排序算法的稳定性 #
排序算法的稳定性指,当元素列表中有相等的元素时,相等元素的相对次序是否固定不变,如果相对次序固定不变,则排序算法是稳定的,反之亦然。
常见的几种排序算法的稳定性表现如下:
冒泡排序:在冒泡排序中,每次比较两个元素,当元素的大小顺序错误时才会进行交换,如果元素列表中有两个相等的元素,它们最终肯定会相邻在一起,但对它们比较时不会进行交换,相对次序是保持不变的。所以冒泡排序是一种稳定的排序算法。
快速排序:在快速排序的实现过程中,有两个游标从列表的两边向中间移动,游标right向左移动的过程中,如果数据小于基准数据,则会将数据赋值给left游标。在这个过程中,如果有相等的数据,相对位置很可能会发生变化,如 [10, 5, 5] 。所以快速排序是一种不稳定的排序算法。
插入排序:在插入排序中,每次将一个未排序的数据插入到已排序序列中,插入的方式是从后到前依次比较和交换,如果元素列表中有两个相等的元素,不会进行交换,相对次序是保持不变的。所以插入排序是一种稳定的排序算法。
希尔排序:在希尔排序中,会进行多次分组插入排序,每一次组内的插入排序是稳定的,不会改变元素的相对次序。但在多次的分组排序中,相同的元素在各自的组内插入排序中移动,相对次序很可能会被打乱。所以希尔排序是一种不稳定的排序算法。
选择排序:在选择排序中,每次都是选择未排序序列中的最小元素,交换到未排序序列的起始位置。存在相等的元素时,如果最小的元素都比它们靠后,最小的元素与相对位置靠前的元素进行交换,则它们的相对位置就发生了变化。如 [10, 10, 5],进行选择排序后两个 10 的相对位置发生了变化。所以选择排序是一种不稳定的排序算法。
堆排序:在堆排序中,会交换节点与子节点,如果有相等的数据,可能会改变相等数据的相对次序。所以堆排序是一种不稳定的排序算法。
归并排序:在归并排序合并的过程中,如果有相等的数据,会先添加左表的数据到新列表中,再添加右表的数据,这不会改变相等数据的相对位置。所以归并排序是一种稳定的排序算法。
桶排序:根据桶排序的排序原理,会将待排序列表进行分桶、桶内排序和合并。在对每一个桶进行桶内排序时,可以采用不同的排序算法,有些排序算法是稳定的,有些排序算法是不稳定,这会影响到桶排序的稳定性。所以桶排序的稳定性取决于桶内排序算法的稳定性。
计数排序:根据计数排序的应用场景,待排序列表中有很多值相等的元素。不过,计数排序没有比较待排序列表中的数据大小,也没有进行位置交换,相等数据的相对次序是保持不变的。所以计数排序是一种稳定的排序算法。
可以通过以下程序对三种常见的排序算法(冒泡排序,快速排序,插入排序)的稳定性进行实验探索:
import numpy as np import time import random def bubblesort(a): #冒泡排序 n=len(a) ind=[k for k in range(len(a))]#建立一个索引矩阵 for i in range(n): for j in range(0,n-i-1): if a[j]>a[j+1]: a[j],a[j+1]=a[j+1],a[j]#交换位置 ind[j],ind[j+1]=ind[j+1],ind[j]#交换位置 return a,ind def quicksortind(a,ind,start,end): #ind = [k for k in range(len(a))] #建立一个索引矩阵 if start>=end:#当子序列包含一个或0个点的时候,停止排序,认为排序完成 return base=a[start]#选取一个种子点,一般从最左边开始 #left=0#初始的左index #right=n-1#初始的右index left,right=start,end while left<right:#第一次能否进入循环的判断 while a[right]>=base and left<right:#进入循环后,right值在不断变化,需要重新添加跳出循环的条件(and left<right) right-=1 a[left]=a[right]#当右指针检索到小于base的数值时,暂停检索,并将其数值赋值给左指针位置的数值 ind[left],ind[right]=ind[right],ind[left]#交换索引 while a[left]<=base and left<right: left+=1 a[right]=a[left]#当左指针检索到大于base的数值时,暂停检索,并将其数值赋值给右指针位置的数值 ind[right],ind[left]=ind[left],ind[right]#交换索引 a[left]=base#当left=right时,把base插入left位置,完成第一轮排序 ind[left],ind[start]=ind[start],ind[left] #以下用递归思想依次对子序列进行快速排序(重复上述操作) quicksortind(a,ind,start,left-1) quicksortind(a,ind,left+1,end) def insertsort(a):# 插入排序 l = len(a) min_index = 0 ind = [k for k in range(len(a))] for i in range(1, l): value = a[i] # 保存新的未排序的点的值 j = i - 1 # 已排序的最后一个数(前一个) #min_value = a[i] while j >= 0 and a[j+1] < a[j]: a[j + 1], a[j] = a[j], a[j + 1] ind[j + 1], ind[j] = ind[j], ind[j + 1] j -= 1 return a,ind ''' 稳定性比较 ''' if __name__=='__main__': a = [5, 5, 5, 4, 2, 3, 2, 4, 3] a1,ind1=bubblesort(a) print(a1) print(ind1) a = [5, 5, 5, 4, 2, 3, 2, 4, 3] ind = [k for k in range(len(a))] # 建立一个索引矩阵 quicksortind(a,ind, 0, len(a) - 1) print(a) print(ind) a=[5,5,5,4,2,3,2,4,3] a3,ind3=insertsort(a) print(a3) print(ind3)
小结 #
掌握python内置函数sort(),sorted()的用法
巩固并加深对不同排序算法的理解
习题 #
- 习题1:使用pyton内置函数对列表list=[10, 17, 50, 7, 30, 24, 27, 45, 15, 5, 36, 21]进行排序
- 习题2:简述排序算法的分类,及几种常见排序算法所属的类别