码农如何轻松玩转排序算法?十大排序复习(上)
2023-12-23 01:45:59
排序算法:计算机世界中的排序魔法师
在计算机科学中,排序算法扮演着整理和组织数据的关键角色。无论是在数据库管理、数据挖掘还是人工智能中,排序算法都是不可或缺的工具。让我们一起探索十种经典的排序算法,了解它们的原理、优缺点以及在不同场景下的应用。
冒泡排序:简单粗暴的泡沫狂欢
冒泡排序是一种直观且容易理解的算法。它就像一串不断翻滚的泡沫,较小的泡沫会不断浮到顶部。算法的核心是比较相邻元素,将较小的元素移到前面。虽然简单,但冒泡排序效率较低,时间复杂度为 O(n²),这意味着随着数据量的增加,其运行时间会急剧增长。
def bubble_sort(arr):
for i in range(len(arr) - 1):
for j in range(len(arr) - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
选择排序:每次选出最小值
选择排序也是一种简单算法,它会找到序列中最小值,然后将其与序列开头元素交换。这个过程重复进行,直到整个序列有序。与冒泡排序类似,选择排序的效率也不高,时间复杂度同样为 O(n²)。
def selection_sort(arr):
for i in range(len(arr)):
min_idx = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
插入排序:有序序列中的逐个插入
插入排序将待排序元素逐个插入到一个已经有序的序列中。这个过程就像在一个装满球的盒子中插入一个新球,需要找到一个合适的空隙来安置新球。插入排序的时间复杂度为 O(n²),但当序列接近有序时,其效率会大大提高。
def insertion_sort(arr):
for i in range(1, len(arr)):
current_element = arr[i]
j = i - 1
while j >= 0 and current_element < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = current_element
希尔排序:插入排序的升级版
希尔排序是对插入排序的改进版本。它将待排序序列分割成多个子序列,然后对每个子序列进行插入排序。最后再将所有子序列合并成一个有序序列。希尔排序的时间复杂度为 O(n¹³),比插入排序要快得多。
def shell_sort(arr):
gap = len(arr) // 2
while gap > 0:
for i in range(gap, len(arr)):
current_element = arr[i]
j = i
while j >= gap and current_element < arr[j - gap]:
arr[j] = arr[j - gap]
j -= gap
arr[j] = current_element
gap //= 2
归并排序:分而治之的排序之王
归并排序是一种分而治之的算法,将待排序序列分割成更小的子序列,对子序列分别进行排序,然后合并子序列得到最终有序序列。归并排序的时间复杂度为 O(n log n),是所有排序算法中最快的算法之一。
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left_half = merge_sort(arr[:mid])
right_half = merge_sort(arr[mid:])
return merge(left_half, right_half)
def merge(left, right):
merged = []
left_index = right_index = 0
while left_index < len(left) and right_index < len(right):
if left[left_index] <= right[right_index]:
merged.append(left[left_index])
left_index += 1
else:
merged.append(right[right_index])
right_index += 1
merged.extend(left[left_index:])
merged.extend(right[right_index:])
return merged
快速排序:速度惊人的分治算法
快速排序也是一种分而治之算法,它选择一个基准元素,将序列分割成两个子序列,一个子序列包含所有小于基准元素的元素,另一个子序列包含所有大于基准元素的元素。然后分别对两个子序列进行快速排序,最后合并两个子序列。快速排序的时间复杂度同样为 O(n log n)。
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
堆排序:基于堆数据结构的排序
堆排序使用堆数据结构对序列进行排序。堆是一种特殊的树形结构,其中每个节点都比其子节点大。堆排序通过不断将堆顶元素与序列最后一个元素交换,然后重新构建堆,从而得到一个有序序列。堆排序的时间复杂度为 O(n log n)。
def heap_sort(arr):
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
n = len(arr)
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
for i in range(n - 1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
计数排序:适用于范围较小的整数
计数排序是一种非比较排序算法,适用于元素范围较小的整数序列。它通过计算每个元素出现的次数,然后根据这些计数来生成一个有序序列。计数排序的时间复杂度为 O(n + k),其中 k 是元素的范围。
def counting_sort(arr, max_value):
n = len(arr)
output = [0] * n
count = [0] * (max_value + 1)
for i in range(n):
count[arr[i]] += 1
for i in range(1, max_value + 1):
count[i] += count[i - 1]
i = n - 1
while i >= 0:
output[count[arr[i]] - 1] = arr[i]
count[arr[i]] -= 1
i -= 1
for i in range(n):
arr[i] = output[i]
桶排序:适用于元素范围较小的非整数
桶排序也是一种非比较排序算法,适用于元素范围较小的非整数序列。它将待排序序列分割成多个桶,然后对每个桶中的元素进行排序,最后合并所有桶中的元素得到有序序列。桶排序的时间复杂度为 O(n + k),其中 k 是元素的范围。
def bucket_sort(arr, n, max_value):
bucket_size = max_value / n
buckets = [[] for _ in range(n)]
for i in range(n):
idx = int(arr[i] / bucket_size)
buckets[idx].append(arr[i])
for bucket in buckets:
bucket.sort()
i = 0
for bucket in buckets:
for value in bucket:
arr[i] = value
i += 1
基数排序:快速排序大整数
基数排序是一种非比较排序算法,适用于大整数序列。它将元素按位进行排序,从最低位到最高位逐次进行。基数排序的时间复杂度为