排序算法是计算机科学中的基本算法之一,用于将一组元素按照一定顺序排列。快速排序、归并排序和堆排序是三种常见的排序算法,各有其特点和适用场景。
快速排序 (Quick Sort)
快速排序是一种经典的分而治之的排序算法。其基本思想是选择一个基准元素,将数组分成两个子数组,小于基准的放在左边,大于基准的放在右边,然后对左右子数组递归地应用同样的方法。
实现
def quick_sort(arr):
if len(arr) <= 1:
return arr
stack = [(0, len(arr) - 1)] # 使用栈来保存待排序子数组的起始和结束索引
while stack:
low, high = stack.pop() # 取出栈顶的子数组范围
if low < high:
pivot = arr[high] # 选取最后一个元素作为基准
left = low - 1 # 左指针
for right in range(low, high): # 右指针
if arr[right] <= pivot:
left += 1
arr[left], arr[right] = arr[right], arr[left]
arr[left + 1], arr[high] = arr[high], arr[left + 1] # 将基准元素放到正确的位置
# 将左右子数组的范围入栈
stack.append((low, left))
stack.append((left + 2, high))
return arr
复杂度与稳定性
- 时间复杂度:平均情况下为O(nlogn),最坏情况下为O(n^2)。
- 空间复杂度:O(logn)。
- 稳定性:不稳定。
归并排序 (Merge Sort)
归并排序是另一种分而治之的排序算法,其基本思想是将数组递归地分成两个子数组,分别排序,然后将已排序的子数组合并起来。
实现
def merge_sort(arr):
if len(arr) <= 1:
return arr
else:
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 = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
merged.extend(left[i:])
merged.extend(right[j:])
return merged
复杂度与稳定性
- 时间复杂度:始终为O(nlogn)。
- 空间复杂度:O(n)。
- 稳定性:稳定。
堆排序 (Heap Sort)
堆排序是一种基于二叉堆的选择排序。它利用堆的性质将数组构建成一个最大堆(或最小堆),然后逐步取出堆顶元素并调整堆,直到整个数组有序。
实现
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)
def heap_sort(arr):
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(nlogn)。
- 空间复杂度:O(1)。
- 稳定性:不稳定。
结论
- 快速排序在平均情况下性能优秀,但在最坏情况下性能较差。
- 归并排序始终保持O(nlogn)的时间复杂度,适用于大规模数据的排序。
- 堆排序是一种原地排序算法,不需要额外的存储空间,但不是稳定的排序算法。
7.彩蛋
关注公众号,获取更多AI算法、工程实践相关的精彩内容~