排序 Sort
1、冒泡排序 BubbleSort
(1) 冒泡排序多次遍历列表。它比较相邻的元素,将不合顺序的交换。每一轮遍历都将下一个最大值放到正确的位置上。时间复杂度是 O ( n 2 ) O(n^2 ) O(n2)。
def BubbleSort(nums: list):
for i in range(len(nums)-1, 0, -1):
for j in range(i):
if nums[j] > nums[j+1]:
nums[j], nums[j+1] = nums[j+1], nums[j]
return nums
(2) 鸡尾酒排序奇数次寻找最大值,偶数次寻找最小值。适用于渴望单次获得最大值最小值的情况。时间复杂度是 O ( n 2 ) O(n^2 ) O(n2)。
def BubbleSort2(lst: list):
L, R = 0, len(lst)-1
for j in range(len(lst)-1, 0, -1):
if (j-len(lst)+1) %2:
for i in range(R-1, L-1, -1):
if lst[i+1] < lst[i]:
lst[i], lst[i+1] = lst[i+1], lst[i]
L += 1
else:
for i in range(L, R, 1):
if lst[i] > lst[i+1]:
lst[i], lst[i+1] = lst[i+1], lst[i]
R -= 1
return lst
(3) 短冒泡排序在遇到已排序列表时会跳出。最优时间复杂度为 O ( n ) O(n) O(n),最坏时间复杂度还是 O ( n 2 ) O(n^2) O(n2)。
def shortBubbleSort(lst: list):
l = len(lst)
if l <= 1: return lst
for i in range(l-1, 0, -1):
flag = False
for j in range(i):
if lst[j] > lst[j+1]:
lst[j], lst[j+1] = lst[j+1], lst[j]
flag = True
if not flag: return lst
2、选择排序 SelectionSort
(1) 选择排序是冒泡排序的修改。每一轮遍历都只找出最大值放到正确的位置上。时间复杂度是 O ( n 2 ) O(n^2 ) O(n2)。
def SelectionSort(List):
for i in range(len(List)-1, 0, -1):
Max = 0
for j in range(i):
if List[j+1] > List[Max]:
Max = j+1
List[i], List[Max] = List[Max], List[i]
3、插入排序 InsertionSort
(1) 插入排序在列表较低的一端维护一个有序的子列表,并逐个将每个新元素“插入”这个子列表。时间复杂度是 O ( n 2 ) O(n^2 ) O(n2)。
def InsertionSort(List):
for i in range(1, len(List)):
temp = List[i]
j = i
while j >= 1 and List[j-1] > temp:
List[j] = List[j-1]
j -= 1
List[j] = temp
4、希尔排序 ShellSort
(1) 希尔排序也称“递减增量排序”,它对插入排序做了改进,将列表按照步长分成数个子列表,并对每一个子列表应用插入排序。对于固定增量, δ ≤ ∣ L i s t ∣ δ\leq\sqrt{|List|} δ≤∣List∣, g a p = ∣ L i s t ∣ / / δ gap={|List|} //δ gap=∣List∣//δ。时间复杂度是 O ( n 3 / 2 ) O(n^{3/2}) O(n3/2)。
def ShellSort(List, delta):
gap = len(List) // delta
while gap > 0:
for start in range(gap):
for i in range(start+gap, len(List), gap):
temp = List[i]
j = i
while j >= gap and List[j-gap] > temp:
List[j] = List[j-gap]
j -= gap
List[j] = temp
gap //= delta
5、归并排序 MergeSort
(1) 归并排序使用分治策略,将列表不断一分为二,然后递归调用归并排序。归并是指将两个较小的有序列表归并为一个有序列表的过程。时间复杂度是 O ( n l o g n ) O(nlog n) O(nlogn)。
def MergeSort(List):
def _sort(L, R, List):
if L != R:
mid = (L+R) // 2
_sort(L, mid, List)
_sort(mid+1, R, List)
i = L; j = mid+1
s = []
while i <= mid and j <= R:
if List[i] < List[j]:
s.append(List[i]); i += 1
else:
s.append(List[j]); j += 1
while i <= mid:
s.append(List[i]); i += 1
while j <= R:
s.append(List[j]); j += 1
for i in range(len(s)):
List[L+i] = s[i]
_sort(0, len(List)-1, List)
6、快速排序 QuickSort
(1) 快速排序使用分治策略,但不使用额外的存储空间。选取基准值,通过首尾指针判断大小找到基准值的正确位置,接着把列表一分为二递归调用。时间复杂度是 O ( n l o g n ) O(nlog n) O(nlogn)。
def QuickSort(List):
def _sort(List, first, last):
if last > first:
split = partition(List, first, last)
_sort(List, first, split-1)
_sort(List, split+1, last)
_sort(List, 0, len(List)-1)
def partition(List, first, last):
datum = List[first] #基准值
if last-first > 3: #三数取中法:取前三个数的中值作为基准值。
d1,d2 = List[first+1],List[first+2]
d1,d2 = (d1,d2) if d1>d2 else (d2,d1)
datum=min(d1,datum); datum=max(d2,datum)
left = first+1
right = last
done = False
while not done:
while left <= right and List[left] <= datum:
left += 1
while List[right] >= datum and right >= left:
right -= 1
if right < left: done = True
else: List[left],List[right] = List[right],List[left]
List[first], List[right] = List[right], List[first]
return right
7、堆排序 heapq模块
heapq里接口操作的对象是list。逻辑结构为一个完全二叉树。时间复杂度是 O ( n l o g n ) O(nlog n) O(nlogn)。
import heapq
#添加元素。
heapq.heappush(heap:list, item:float)
'''
data = [97, 38, 27, 50, 76, 65, 49, 13]
heap = []
for n in data:
heapq.heappush(heap, n)'''
#列表堆化重排
heapq.heapify(List:list)
'''
data = [97, 38, 27, 50, 76, 65, 49, 13]
heapq.heapify(data)'''
#删除并返回堆顶元素,即heap中最小的元素。
heapq.heappop(heap:list)
#替换并返回堆顶元素。
heapreplace(heap:list, item:float)
#添加元素,并返回重新堆化后的堆顶元素。
heapq.heappushpop(heap:list, item:float)
#merge是多路归并排序。
heapq.merge(heap:list[,heap:list [,heap:list [...]]])
#获取最大或者最小的n个数。
heapq.nlargest(n, iterable, key=None)
#结果上等价于sorted(iterable, key=key, reverse=True)[:n]
heapq.nsmallest(n, iterable, key=None)
#结果上等价于sorted(iterable, key=key)[:n]
8、桶排序 BucketSort
桶排序特别浪费空间。时间复杂度是 O ( n ) O(n) O(n)。
def BucketSort(nums):
minv, maxv = min(nums), max(nums)
countn = [0]*(maxv-minv+1)
for i in nums:
countn[i-minv] += 1
n = 0
for i in range(len(countn)):
p=countn[i]
while countn[i] and p:
nums[n]=i+minv
n += 1; p-=1
完整代码下载地址:Python版数据结构与算法-排序算法