前言:算法中排序也是经常用到的,今天学习排序的几大经典算法(python语言实现)。
目录
冒泡排序
代码解读
时间复杂度分析
选择排序
代码解读
时间复杂度分析
插入排序
代码解读
时间复杂度分析
希尔排序
代码解读
时间复杂度分析
归并排序
代码解读
时间复杂度分析
快速排序
代码解读
时间复杂度分析
桶排序
代码解读
时间复杂度分析
计数排序
代码解读
时间复杂度分析
基数排序
代码解读
时间复杂度分析
堆排序
代码解读
时间复杂度分析
总结
1.1 冒泡排序 | 菜鸟教程 (runoob.com)
代码:
def bubble_sort(alist):
n = len(alist)
for i in range(n - 1, -1, -1):
for j in range(0, i):
if alist[j] > alist[j + 1]:
alist[j], alist[j + 1] = alist[j + 1], alist[j]
case:[22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70]
O(N^2)
有两层for循环, 看一下最差的情况
外层for循环,执行次数为N
内层for循环,第一次比较了n-1,第二次比较了n-2,……,第N-1次比较了1次,加起来,总的执行次数复杂度为N
复杂度为N*2
1.2 选择排序 | 菜鸟教程 (runoob.com)
def select_sort(alist):
n = len(alist)
for j in range(n - 1):
min_index = j
for i in range(j + 1, n):
if alist[min_index] > alist[i]:
min_index = i
alist[j], alist[min_index] = alist[min_index], alist[j]
case:[22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70]
时间复杂度:N^2
循环了两次,外层循环和内层循环,时间复杂度为N^2
1.3 插入排序 | 菜鸟教程 (runoob.com)
def InsertionSort(aList):
n = len(aList)
for i in range(1, n):
x = aList[i]
j = i - 1
while j >= 0:
if x <= aList[j]:
aList[j + 1] = aList[j]
j -= 1
else:
break
aList[j + 1] = x
case:[22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70]
N^2
需要循环两次,时间复杂度为N^2
1.4 希尔排序 | 菜鸟教程 (runoob.com)
def ShellSort(aList):
n = len(aList)
gap = n // 2
while gap > 0:
for i in range(gap, n):
x = aList[i]
j = i
while j >= gap:
if x < aList[j - gap]:
aList[j] = aList[j - gap]
else:
break
j -= gap
aList[j] = x
print(aList)
gap = gap // 2
希尔排序时间复杂度有点复杂,排序的效率是取决于它的增量序列。时间复杂度在O(nlogn~n^2)之间
1.5 归并排序 | 菜鸟教程 (runoob.com)
def Merge(aList, start, mid, end):
tmp = []
L = start
r = mid + 1
while L <= mid and r <= end:
if aList[L] <= aList[r]:
tmp.append(aList[L])
L += 1
else:
tmp.append(aList[r])
r += 1
tmp.extend(aList[L:mid + 1])
tmp.extend(aList[r:end + 1])
for i in range(start, end + 1):
aList[i] = tmp[i - start]
print(start, end, tmp)
def MergeSort(aList, start, end):
if start == end:
return
mid = (start + end) // 2
MergeSort(aList, start, mid)
MergeSort(aList, mid + 1, end)
Merge(aList, start, mid, end)
O(NlogN)
归并排序用到了递归和分治的思想,列表长度为N,用二分法分解,为logN,合在一起,复杂度是O(NlogN)
1.6 快速排序 | 菜鸟教程 (runoob.com)
def QucikSortPivot(aList, start, end):
pivot = start
j = start + 1
for i in range(start + 1, end + 1):
if aList[i] <= aList[pivot]:
aList[i], aList[j] = aList[j], aList[i]
j += 1
aList[pivot], aList[j - 1] = aList[j - 1], aList[pivot]
pivot = j - 1
print(aList[pivot], aList[start:pivot], aList[pivot + 1:end + 1])
return pivot
def QuickSort(aList, start, end):
if start >= end:
return
pivot = QucikSortPivot(aList, start, end)
QuickSort(aList, start, pivot - 1)
QuickSort(aList, pivot + 1, end)
随机快速排序
import random
def QucikSortPivot(aList, start, end):
randIndex = random.randint(start,end)
aList[start],aList[randIndex] = aList[randIndex],aList[start]
pivot = start
j = start + 1
for i in range(start + 1, end + 1):
if aList[i] <= aList[pivot]:
aList[i], aList[j] = aList[j], aList[i]
j += 1
aList[pivot], aList[j - 1] = aList[j - 1], aList[pivot]
pivot = j - 1
print(aList[pivot], aList[start:pivot], aList[pivot + 1:end + 1])
return pivot
def QuickSort(aList, start, end):
if start >= end:
return
pivot = QucikSortPivot(aList, start, end)
QuickSort(aList, start, pivot - 1)
QuickSort(aList, pivot + 1, end)
最坏时间复杂度:O(N^2)
1.9 桶排序 | 菜鸟教程 (runoob.com)
def SelectSort(aList):
n = len(aList)
for i in range(0, n):
min = i
for j in range(i + 1, n):
if aList[j] < aList[min]:
min = j
aList[i], aList[min] = aList[min], aList[i]
def BucketSort(aList):
minV = min(aList)
maxV = max(aList)
bucketCount = 3
bucket = [[], [], []]
perBucket = (maxV - minV + bucketCount) // bucketCount
for num in aList:
buketIndex = (num - minV) // perBucket
bucket[buketIndex].append(num)
for i in range(bucketCount):
SelectSort(bucket[i])
index = 0
for i in range(bucketCount):
for v in bucket[i]:
aList[index] = v
index += 1
O(N^2)
最坏情况时间复杂度是O(N^2)
1.8 计数排序 | 菜鸟教程 (runoob.com)
def CountingSort(aList):
n = len(aList)
countLen = max(aList) + 1
count = [0] * countLen
for val in aList:
count[val] += 1
print(count)
n = 0
for val in range(0, countLen):
while count[val] > 0:
count[val] -= 1
aList[n] = val
n += 1
O(n+k)
第一次遍历数组,时间复杂度:O(n),第二次遍历计数器,(如果有k个计数器)时间复杂度O(K),加起来,时间复杂度为:O(n+k)
1.10 基数排序 | 菜鸟教程 (runoob.com)
def RadixSort(aList):
base = 1
maxv = max(aList)
while base < maxv:
bucket = []
for index in range(10):
bucket.append([])
for num in aList:
index = num // base % 10
bucket[index].append(num)
L = 0
for index in range(10):
for v in bucket[index]:
aList[L] = v
L += 1
print(aList)
base *= 10
O(n*k)
时间复杂度:O(n*k),其中n是输入元素的数量,k是数字的最大位数。
1.7 堆排序 | 菜鸟教程 (runoob.com)
def maxHeapify(heap, start, end):
son = start * 2
while son <= end:
if son + 1 <= end and heap[son + 1] > heap[son]:
son += 1
if heap[son] > heap[start]:
heap[start], heap[son] = heap[son], heap[start]
start, son = son, son * 2
else:
break
def HeapSort(aList):
heap = [None] + aList
root = 1
L = len(heap)
for i in range(L // 2, root - 1, -1):
maxHeapify(heap, i, L - 1)
for i in range(L - 1, root, -1):
heap[i], heap[root] = heap[root], heap[i]
maxHeapify(heap, root, i - 1)
return heap[root:]
先来看看什么是堆,推荐阅读下面的这篇博客
大顶堆,小顶堆_这瓜保熟么的博客-CSDN博客
建堆的时间复杂度为O(n),排序重建堆的时间复杂度为nlog(n),总的时间复杂度为O(nlogn)
针对具体的序列,每种排序算法复杂度都不同,具体要用到哪种排序算法,要结合实际案例,针对每种算法的时间复杂度的分析和应用,后面再做一下总结,此外,每种排序算法的代码要加以理解巩固!多练习几遍排序算法,达到熟练使用的程度。“无他,唯手熟尔”!