本文中实现的排序算法均按照从小到大的顺序,待排序的数取一般整数。
选择排序
从前到后逐渐有序,每次遍历都会把无序部分的最小值往前“提”
def select(nums: List[int]) -> List[int]:
n = len(nums)
for i in range(n - 1):
k = i
for j in range(i + 1, n):
if nums[j] < nums[k]:
k = j
if k > i:
nums[i], nums[k] = nums[k], nums[i]
return nums
复制代码
冒泡排序
从后到前逐渐有序,每次遍历都会把无序部分的最大值向后“顶”。
def bubble(nums: List[int]) -> List[int]:
n = len(nums)
for i in range(n - 1):
for j in range(1, n - i):
if nums[j] < nums[j - 1]:
nums[j], nums[j - 1] = nums[j - 1], nums[j]
return nums
复制代码
插入排序
从前到后逐渐有序,将每次遍历到的值"插"入前方的有序部分。
def insert(nums: List[int]) -> List[int]:
for i in range(1, len(nums)):
for j in reversed(range(i)):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
return nums
复制代码
归并排序
自顶向下递归,自底向上有序。两两比较,组组归并。
def merge(nums: List[int]) -> List[int]:
def _merge(nums1: List[int], nums2: List[int]):
i, j, res = 0, 0, []
while i < len(nums1) and j < len(nums2):
if nums1[i] < nums2[j]:
res.append(nums1[i])
i += 1
else:
res.append(nums2[j])
j += 1
while i < len(nums1):
res.append(nums1[i])
i += 1
while j < len(nums2):
res.append(nums2[j])
j += 1
return res
if len(nums) <= 1:
return nums
mid = (len(nums) - 1) // 2
return _merge(merge(nums[:mid + 1]), merge(nums[mid + 1:]))
复制代码
希尔排序
跳跃分组结合插入排序,通过逐渐降低数组的无序性提高插入排序的效率。
def shell(nums: List[int]) -> List[int]:
def _sort(array: List[int], index: int, step: int, size: int):
current = index + step
while current < size:
if array[current] < array[current - step]:
front = current - step
while front >= 0 and array[front] > array[front + step]:
array[front], array[front + step] = array[front + step], array[front]
front -= step
current += step
n, k = len(nums), len(nums) // 2
while k > 0:
for i in range(k):
_sort(nums, i, k, n)
k //= 2
return nums
复制代码
快速排序
选取基准左数第一,左小右大移动边界。
小则移动大则交换,基准居中左右递归。
def quick(nums: List[int]) -> List[int]:
def _quick(array: List[int], start: int, close: int):
if start >= close:
return
bound = start + 1
for index in range(bound, close + 1):
if array[index] < array[start]:
array[index], array[bound] = array[bound], array[index]
bound += 1
base = bound - 1
array[start], array[base] = array[base], array[start]
_quick(array, start, base - 1)
_quick(array, base + 1, close)
_quick(nums, 0, len(nums) - 1)
return nums
复制代码
堆排序
形如第K大的数之类的问题,快排优于堆排。
形如前K大的数之类的问题,选择堆排更佳。
如果K不大于3,上述问题不过O(N)复杂度。
def heap(nums: List[int]) -> List[int]:
def heapify(array: List[int], index: int, size: int):
i_max = index
il, ir = 2 * index + 1, 2 * index + 2
if il < size and array[il] > array[i_max]:
i_max = il
if ir < size and array[ir] > array[i_max]:
i_max = ir
if index != i_max:
array[index], array[i_max] = array[i_max], array[index]
heapify(array, i_max, size)
n = len(nums)
for i in reversed(range(n // 2)):
heapify(nums, i, n)
for k in reversed(range(1, n)):
nums[0], nums[k] = nums[k], nums[0]
heapify(nums, 0, k)
return nums
复制代码
桶排序
有序的桶保证了重建后的数组是有序的数组,每次向桶中插入一个值需要保证桶中的数有序。
def bucket(nums: List[int]) -> List[int]:
# 以下实现只适用于0~99范围的整数
buckets = [list() for _ in range(10)]
for num in nums:
_bucket = buckets[num // 10]
_bucket.append(num)
n = len(_bucket)
for i in reversed(range(1, n)):
if _bucket[i] < _bucket[i - 1]:
_bucket[i], _bucket[i - 1] = _bucket[i - 1], _bucket[i]
res = []
for _bucket in buckets:
res.extend(_bucket)
return res
复制代码
计数排序
计数排序是一个统计和重现的过程,适用于待排序数取值范围非常有限的场景,例如十分制比赛中选手的排名。
def count(nums: List[int]) -> List[int]:
counter = [0 for _ in range(10)]
for num in nums:
counter[num] += 1
res = []
for num, _count in enumerate(counter):
for _ in range(_count):
res.append(num)
return res
复制代码
基数排序
将所有数先按个位排序,再按十位排序,再按百位排序......每次排序都是一次桶的分发和收集。
def radix(nums: List[int], figure: int) -> List[int]:
# figure表示待排序数的最大位数
# 如[1, 10, 100], figure取3
buckets = [list() for _ in range(10)]
dev, mod = 1, 10
for i in range(figure):
for x in nums:
k = (x % mod) // dev
buckets[k].append(x)
nums.clear()
for bucket in buckets:
for x in bucket:
nums.append(x)
bucket.clear()
dev *= 10
mod *= 10
return nums
复制代码