Python十大排序方式(详解+示例+查询链接)
文章目录
- Python十大排序方式(详解+示例+查询链接)
- 1 冒泡排序(Bubble Sort):
- 2 选择排序(Selection Sort):
- 3 插入排序(Insertion Sort):
- 4 堆排序(Heap Sort):
- 5 归并排序(Merge Sort):
- 6 快速排序(Quick Sort):
- 7 希尔排序(Shell Sort):
- 8 计数排序(Counting Sort):
- 9 桶排序(Bucket Sort):
- 10 基数排序(Radix Sort):
- 11 更多
1 冒泡排序(Bubble Sort):
- 基本思想:重复地遍历数组,比较相邻的两个元素,如果它们的顺序错误就交换它们,直到数组完全有序。
- 时间复杂度:最好情况是O(n),当数组已经有序时;最坏情况是O(n2),当数组逆序时;平均情况是O(n2)。
- 空间复杂度:O(1),只需要常数个额外空间。
- 稳定性:稳定的排序算法,保持相等元素的相对顺序。
- 代码示例:
def bubble_sort(array):
n = len(array)
for i in range(n - 1):
swapped = False # 标记是否发生了交换
for j in range(n - 1 - i):
if array[j] > array[j + 1]: # 如果相邻元素顺序错误,就交换它们
array[j], array[j + 1] = array[j + 1], array[j]
swapped = True
if not swapped: # 如果没有发生交换,说明数组已经有序,提前结束循环
break
return array
2 选择排序(Selection Sort):
- 基本思想:在未排序的数组中找到最小(或最大)的元素,将它放到数组的起始位置,然后重复这个过程,直到数组完全有序。
- 时间复杂度:最好情况,最坏情况,平均情况都是O(n^2)。
- 空间复杂度:O(1),只需要常数个额外空间。
- 稳定性:不稳定的排序算法,可能改变相等元素的相对顺序。
- 代码示例:
def selection_sort(array):
n = len(array)
for i in range(n - 1):
min_index = i # 记录最小元素的索引
for j in range(i + 1, n):
if array[j] < array[min_index]: # 如果找到更小的元素,更新最小元素的索引
min_index = j
if min_index != i: # 如果最小元素不在起始位置,就交换它们
array[i], array[min_index] = array[min_index], array[i]
return array
3 插入排序(Insertion Sort):
- 基本思想:将数组分为已排序和未排序的两部分,每次从未排序的部分取出一个元素,插入到已排序的部分的合适位置,直到数组完全有序。
- 时间复杂度:最好情况是O(n),当数组已经有序时;最坏情况是O(n2),当数组逆序时;平均情况是O(n2)。
- 空间复杂度:O(1),只需要常数个额外空间。
- 稳定性:稳定的排序算法,保持相等元素的相对顺序。
- 代码示例:
def insertion_sort(array):
n = len(array)
for i in range(1, n):
key = array[i] # 取出未排序部分的第一个元素
j = i - 1 # 已排序部分的最后一个元素的索引
while j >= 0 and array[j] > key: # 从后往前遍历已排序部分,找到合适的插入位置
array[j + 1] = array[j] # 将大于key的元素后移一位
j -= 1
array[j + 1] = key # 将key插入到正确的位置
return array
4 堆排序(Heap Sort):
- 基本思想:利用堆这种数据结构的性质,将数组构建成一个大顶堆(或小顶堆),然后将堆顶元素与堆尾元素交换,缩小堆的范围,再调整堆,重复这个过程,直到堆的大小为1,此时数组完全有序。
- 时间复杂度:最好情况,最坏情况,平均情况都是O(nlogn)。
- 空间复杂度:O(1),只需要常数个额外空间。
- 稳定性:不稳定的排序算法,可能改变相等元素的相对顺序。
- 代码示例:
def heap_sort(array):
n = len(array)
# 构建大顶堆
for i in range(n // 2 - 1, -1, -1): # 从最后一个非叶子节点开始,自下而上,自右而左调整堆
heapify(array, n, i)
# 排序
for i in range(n - 1, 0, -1): # 从堆尾到堆顶,依次将堆顶元素与堆尾元素交换,然后调整堆
array[0], array[i] = array[i], array[0]
heapify(array, i, 0) # 调整堆的大小为i,堆顶索引为0
return array
def heapify(array, n, i): # 调整堆的大小为n,堆顶索引为i
largest = i # 记录最大元素的索引
left = 2 * i + 1 # 左孩子的索引
right = 2 * i + 2 # 右孩子的索引
if left < n and array[left] > array[largest]: # 如果左孩子大于父节点,更新最大元素的索引
largest = left
if right < n and array[right] > array[largest]: # 如果右孩子大于父节点,更新最大元素的索引
largest = right
if largest != i: # 如果最大元素不是父节点,就交换它们,并递归地调整子树
array[i], array[largest] = array[largest], array[i]
heapify(array, n, largest)
5 归并排序(Merge Sort):
- 基本思想:利用分治的思想,将数组分为两个子数组,分别对它们进行排序,然后将两个有序的子数组合并成一个有序的数组,重复这个过程,直到数组的大小为1,此时数组完全有序。
- 时间复杂度:最好情况,最坏情况,平均情况都是O(nlogn)。
- 空间复杂度:O(n),需要一个与原数组大小相同的辅助数组。
- 稳定性:稳定的排序算法,保持相等元素的相对顺序。
- 代码示例:
def merge_sort(array):
n = len(array)
if n <= 1: # 如果数组大小为1,直接返回
return array
mid = n // 2 # 找到数组的中点
left = merge_sort(array[:mid]) # 对左半部分进行排序
right = merge_sort(array[mid:]) # 对右半部分进行排序
return merge(left, right) # 合并两个有序的子数组
def merge(left, right): # 合并两个有序的子数组
i = 0 # 左数组的索引
j = 0 # 右数组的索引
k = 0 # 辅助数组的索引
n1 = len(left) # 左数组的大小
n2 = len(right) # 右数组的大小
temp = [0] * (n1 + n2) # 辅助数组,大小为两个
6 快速排序(Quick Sort):
- 基本思想:利用分治的思想,选择一个基准元素(pivot),将数组分为两个子数组,使得左边的子数组中的元素都小于等于基准元素,右边的子数组中的元素都大于等于基准元素,然后对两个子数组递归地进行快速排序,直到数组的大小为1或0,此时数组完全有序。
- 时间复杂度:最好情况是O(nlogn),当每次选择的基准元素能够平均划分数组时;最坏情况是O(n^2),当每次选择的基准元素是数组的最大或最小元素时;平均情况是O(nlogn)。
- 空间复杂度:O(logn),需要栈空间来存储递归调用的信息。
- 稳定性:不稳定的排序算法,可能改变相等元素的相对顺序。
- 代码示例:
def quick_sort(array, left, right):
if left < right: # 如果数组有至少两个元素
pivot = partition(array, left, right) # 对数组进行划分,返回基准元素的索引
quick_sort(array, left, pivot - 1) # 对左子数组进行快速排序
quick_sort(array, pivot + 1, right) # 对右子数组进行快速排序
return array
def partition(array, left, right):
pivot = array[right] # 选择最右边的元素作为基准元素
i = left # i指向左子数组的末尾
for j in range(left, right): # 遍历除了基准元素以外的元素
if array[j] <= pivot: # 如果当前元素小于等于基准元素
array[i], array[j] = array[j], array[i] # 将当前元素交换到左子数组的末尾
i += 1 # 左子数组的长度加一
array[i], array[right] = array[right], array[i] # 将基准元素交换到左子数组的右边
return i # 返回基准元素的索引
7 希尔排序(Shell Sort):
- 基本思想:基于插入排序的思想,将数组分为若干个子序列,每个子序列的元素相隔一定的间隔(称为增量),对每个子序列进行插入排序,然后逐渐减小增量,重复这个过程,直到增量为1,此时数组完全有序。
- 时间复杂度:取决于增量的选择,最好情况是O(n),当数组已经有序时;最坏情况是O(n2),当增量为1时;平均情况是O(n1.3)。
- 空间复杂度:O(1),只需要常数个额外空间。
- 稳定性:不稳定的排序算法,可能改变相等元素的相对顺序。
- 代码示例:
def shell_sort(array):
n = len(array)
gap = n // 2 # 初始增量为数组长度的一半
while gap > 0: # 当增量大于0时
for i in range(gap, n): # 对每个子序列进行插入排序
key = array[i] # 取出未排序部分的第一个元素
j = i - gap # 已排序部分的最后一个元素的索引
while j >= 0 and array[j] > key: # 从后往前遍历已排序部分,找到合适的插入位置
array[j + gap] = array[j] # 将大于key的元素后移gap位
j -= gap
array[j + gap] = key # 将key插入到正确的位置
gap //= 2 # 减小增量
return array
8 计数排序(Counting Sort):
- 基本思想:假设数组中的元素都是在一个范围内的整数,创建一个与该范围大小相同的辅助数组,统计每个元素出现的次数,然后根据辅助数组中的信息,将元素放到正确的位置,使得数组有序。
- 时间复杂度:O(n+k),其中n是数组的大小,k是数组中元素的范围。
- 空间复杂度:O(n+k),需要一个与原数组大小相同的输出数组,和一个与元素范围大小相同的辅助数组。
- 稳定性:稳定的排序算法,保持相等元素的相对顺序。
- 代码示例:
def counting_sort(array, max_val):
n = len(array)
output = [0] * n # 输出数组,与原数组大小相同
count = [0] * (max_val + 1) # 计数数组,大小为最大值加一,对应0-max_val的数值
for x in array: # 遍历原数组,统计每个数值的出现次数
count[x] += 1
for i in range(1, max_val + 1): # 计算每个数值在输出数组中的结束位置
count[i] += count[i - 1]
for x in reversed(array): # 从后往前遍历原数组,将元素放入输出数组的正确位置
output[count[x] - 1] = x # 将元素放入输出数组的对应位置
count[x] -= 1 # 更新计数数组
for i in range(n): # 将输出数组复制到原数组
array[i] = output[i]
9 桶排序(Bucket Sort):
- 基本思想:假设数组中的元素都是在一个范围内的实数,将该范围划分为若干个相同大小的子区间,称为桶,创建一个与桶的数量相同的辅助数组,每个桶对应一个链表,遍历原数组,将每个元素放入对应的桶中,然后对每个桶中的元素进行排序,最后将所有桶中的元素依次放回原数组,使得数组有序。
- 时间复杂度:O(n+k),其中n是数组的大小,k是桶的数量。如果使用了较好的排序算法对每个桶进行排序,那么一般情况下,桶排序的时间复杂度接近于O(n)。
- 空间复杂度:O(n+k),需要一个与原数组大小相同的输出数组,和一个与桶的数量相同的辅助数组。
- 稳定性:稳定的排序算法,保持相等元素的相对顺序。
- 代码示例:
def bucket_sort(array):
n = len(array)
max_val = max(array) # 数组中的最大值
min_val = min(array) # 数组中的最小值
bucket_range = (max_val - min_val) / n # 每个桶的范围
bucket_list = [[] for _ in range(n + 1)] # 辅助数组,每个桶是一个链表
for x in array: # 遍历原数组,将每个元素放入对应的桶中
bucket_list[int((x - min_val) // bucket_range)].append(x)
i = 0 # 原数组的索引
for bucket in bucket_list: # 遍历辅助数组,对每个桶中的元素进行排序
bucket.sort() # 这里可以
10 基数排序(Radix Sort):
- 基本思想:利用分治的思想,将数组中的元素按照每一位的数值分配到不同的桶中,然后按照桶的顺序收集元素,重复这个过程,直到所有的位都被处理过,此时数组完全有序。
- 时间复杂度:O(d*(n+k)),其中d是数组中元素的最大位数,n是数组的大小,k是桶的数量。
- 空间复杂度:O(n+k),需要一个与原数组大小相同的输出数组,和一个与桶的数量相同的辅助数组。
- 稳定性:稳定的排序算法,保持相等元素的相对顺序。
- 代码示例:
def radix_sort(array):
max_val = max(array) # 数组中的最大值
exp = 1 # 当前处理的位数,从个位开始
while max_val // exp > 0: # 当还有位数未处理时
counting_sort(array, exp) # 对当前位数进行计数排序
exp *= 10 # 处理下一位数
def counting_sort(array, exp): # 根据指定的位数进行计数排序
n = len(array)
output = [0] * n # 输出数组,与原数组大小相同
count = [0] * 10 # 计数数组,大小为10,对应0-9的数值
for x in array: # 遍历原数组,统计每个数值在当前位数上的出现次数
index = (x // exp) % 10 # 计算当前位数上的数值
count[index] += 1
for i in range(1, 10): # 计算每个数值在输出数组中的结束位置
count[i] += count[i - 1]
for x in reversed(array): # 从后往前遍历原数组,将元素放入输出数组的正确位置
index = (x // exp) % 10 # 计算当前位数上的数值
output[count[index] - 1] = x # 将元素放入输出数组的对应位置
count[index] -= 1 # 更新计数数组
for i in range(n): # 将输出数组复制到原数组
array[i] = output[i]
11 更多
如果您想了解更多关于排序算法的信息,您可以访问以下链接:
- Radix Sort (With Code in Python, C++, Java and C) - Programiz
- Python Program for Radix Sort - GeeksforGeeks
- Radix Sort in Python - Stack Abuse
- sorting - Radix sort python grammar - Stack Overflow
- Python Sorting Algorithm: Radix Sort - Python in Plain English