一、冒泡排序(Bubble Sort)
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
下面是完整代码:
def bubble_sort(l): for i in range(len(l)): for j in range(len(l) - i - 1): if l[j] > l[j+1]: l[j], l[j+1] = l[j+1], l[j] return l L = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44] l = bubble_sort(L) print(l)
二.快速排序(Quick Sort)
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
先来看一个称之为伪快排的快排代码:
def quick_sort(array): if len(array) < 2: return array else: pivot = array[0] less_than_pivot = [x for x in array[1:] if x <= pivot] more_than_pivot = [x for x in array[1:] if x > pivot] return quick_sort(less_than_pivot) + [pivot] + quick_sort(more_than_pivot)
这段代码最关键的是pivot这个参数,这段代码里取序列的第一个元素,然后以这个元素为分组的基准,利用列表解析式使得它左边的值都比它小,右边的值都比它大。然后再分别对这些序列进行递归排序。
这段代码虽然短小利于理解,但是其效率很低,主要体现在以下方面:
- 分组基准的选取过于随便,不一定可以取到列表的中间值
- 空间复杂度大,使用了两个列表解析式,而且每次选取进行比较时需要遍历整个序列。
- 若序列长度过于小(比如只有几个元素),快排效率就不如插入排序了。
- 递归影响性能,最好进行优化。
下面是完整代码:
def partition(arr, left, right): key = left # 划分参考数索引,默认为第一个数为基准数,可优化 while left < right: # 如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现 while left < right and arr[right] >= arr[key]: right -= 1 # 如果列表前边的数,比基准数小或相等,则后移一位直到有比基准数大的数出现 while left < right and arr[left] <= arr[key]: left += 1 # 此时已找到一个比基准大的书,和一个比基准小的数,将他们互换位置 (arr[left], arr[right]) = (arr[right], arr[left]) # 当从两边分别逼近,直到两个位置相等时结束,将左边小的同基准进行交换 (arr[left], arr[key]) = (arr[key], arr[left]) # 返回目前基准所在位置的索引 return left def quicksort(arr, left, right): if left >= right: return # 从基准开始分区 mid = partition(arr, left, right) # 递归调用 # print(arr) quicksort(arr, left, mid - 1) quicksort(arr, mid + 1, right) return arr def Quicksort(arr): return quicksort(arr, 0, len(arr)-1) L = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44] l = Quicksort(L) print(l)
三.二路归并排序(Two-way Merge Sort)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列
下面是完整代码:
def merge(arr,left,mid,right): temp=[] #中间数组 i=left #左段子序列起始 j=mid+1 #右段子序列起始 while i<=mid and j<=right: if arr[i]<=arr[j]: temp.append(arr[i]) i+=1 else: temp.append(arr[j]) j+=1 while i<=mid: temp.append(arr[i]) i+=1 while j<=right: temp.append(arr[j]) j+=1 for i in range(left,right+1): # !注意这里,不能直接arr=temp,他俩大小都不一定一样 arr[i]=temp[i-left] #递归调用归并排序 def mSort(arr,left,right): if left>=right: return mid=(left+right)//2 mSort(arr,left,mid) mSort(arr,mid+1,right) merge(arr,left,mid,right) return arr def MSort(arr): return mSort(arr, 0, len(arr)-1) L = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44] l = MSort(L) print(l)