排序算法详解:轻松攻破LeetCode中的排序难题
2022-11-18 20:05:25
掌握 LeetCode 排序算法的终极指南
作为一名程序员,掌握排序算法对于解决众多数据处理问题至关重要。本文将深入探讨 LeetCode 上最常见的 9 种排序算法,从基础的冒泡排序到高级的基数排序,帮助你全面提升算法技能。
1. 冒泡排序:简单易懂,基础扎实
冒泡排序是一种最简单直观的排序算法,它反复比较相邻元素,将较大的元素向后“冒泡”,直至数组有序。其时间复杂度为 O(n^2),空间复杂度为 O(1)。
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]
2. 选择排序:选出最优,逐个击破
选择排序是一种基于比较的排序算法,它反复从数组中选择最小的元素,并将其放在数组的开头。其时间复杂度为 O(n^2),空间复杂度为 O(1)。
def selection_sort(arr):
for i in range(len(arr) - 1):
min_index = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[min_index]:
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i]
3. 插入排序:有序渐进,逐个插入
插入排序是一种基于比较的排序算法,它通过将每个元素逐个插入到前面的有序序列中,从而实现对整个数组的排序。其时间复杂度为 O(n^2),空间复杂度为 O(1)。
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
4. 归并排序:分而治之,有序融合
归并排序是一种基于分治的排序算法,它通过将数组划分为较小的子数组,对子数组进行排序,然后合并子数组以得到最终的排序结果。其时间复杂度为 O(n log n),空间复杂度为 O(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 = 0
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
5. 快速排序:随机枢纽,高效分割
快速排序是一种基于分治的排序算法,它通过选择一个枢纽元素,将数组划分为左右两个子数组,然后对子数组进行递归排序。其时间复杂度为 O(n log n),空间复杂度为 O(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)
6. 堆排序:构建堆结构,逐个取出最大值
堆排序是一种基于堆的数据结构的排序算法,它通过将数组构建成一个二叉堆,然后逐个取出堆顶元素,从而实现对整个数组的排序。其时间复杂度为 O(n log n),空间复杂度为 O(1)。
def heap_sort(arr):
n = len(arr)
# Build a max heap
for i in range(n, -1, -1):
heapify(arr, n, i)
# Sort the array
for i in range(n - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
heapify(arr, i, 0)
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)
7. 计数排序:整数范围,高效计数
计数排序是一种基于计数的排序算法,它适用于整数范围有限的数组。其时间复杂度为 O(n + k),空间复杂度为 O(k),其中k为数组中最大元素与最小元素的差。
def counting_sort(arr):
n = len(arr)
max_value = max(arr)
min_value = min(arr)
range_value = max_value - min_value + 1
count = [0] * range_value
# Store the count of each element
for i in range(n):
count[arr[i] - min_value] += 1
# Store the actual positions of each element in the output array
output = []
for i in range(range_value):
while count[i] > 0:
output.append(i + min_value)
count[i] -= 1
# Copy the output array back to the original array
for i in range(n):
arr[i] = output[i]
8. 桶排序:分桶归类,逐个排序
桶排序是一种基于比较的排序算法,它将数组划分为若干个桶,然后将每个元素放入相应的桶中。每个桶内再进行排序,最后将所有桶中的元素合并为一个有序的数组。其时间复杂度为 O(n + k),空间复杂度为 O(n + k),其中k为桶的数量。
def bucket_sort(arr):
n = len(arr)
max_value = max(arr)
min_value = min(arr)
bucket_size = (max_value - min_value) // n + 1
buckets = [[] for _ in range(bucket_size)]
# Distribute elements into buckets
for i in range(n):
bucket_index = (arr[i] - min_value) // bucket_size
buckets[bucket_index].append(arr[i])
# Sort each bucket
for bucket in buckets:
bucket.sort()
# Concatenate all buckets into a single sorted array
sorted_array = []
for bucket in buckets:
sorted_array.extend(bucket)
return sorted_array
9. 基数排序:逐位比较,稳定排序
基数排序是一种基于计数的排序算法,它适用于整数范围有限的数组。其时间复杂度为 O(n * k),空间复杂度为 O(n + k),其中k为数组中最大元素的位数。
def radix_sort(arr):
max_value = max(arr)
exp = 1
while max_value // exp > 0:
counting_sort(arr, exp)
exp *= 10
常见问题解答
-
哪些排序算法是最快的?
快速排序和归并排序通常被认为是最快的排序算法。 -
哪种排序算法是最稳定的?
基数排序和计数排序是稳定的排序算法,这意味着它们保留了相等元素的相对顺序。 -
哪种排序算法的空间复杂度最低?
冒泡排序、