
基于python代码理解排序算法(冒泡、插入、选择)
算法可视化演示
比较次数
0
交换次数
0
执行时间
0ms
当前步骤
0
冒泡排序
冒泡排序是一种简单的排序算法,它重复地走访过要排序的数列,一次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。
这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端,就像水中的气泡一样向上冒。
工作原理:
- 从数组的第一个元素开始,比较相邻的两个元素
- 如果第一个比第二个大,则交换它们的位置
- 对每一对相邻元素重复同样的工作,从开始第一对到结尾的最后一对
- 完成一轮后,最大的元素会"浮"到数组的末尾
- 针对所有的元素重复以上的步骤,除了最后已经排好序的元素
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
时间复杂度
最佳: O(n)
平均: O(n²)
最坏: O(n²)
空间复杂度
O(1) - 原地排序
稳定性
稳定排序
冒泡排序代码实现 (Python)
def bubble_sort(arr):
n = len(arr)
# 外层循环控制需要进行多少轮比较
for i in range(n - 1):
swapped = False
# 内层循环进行相邻元素的比较和交换
# 每完成一轮,最大的元素已经到位,不需要再比较
for j in range(n - i - 1):
# 比较相邻元素
if arr[j] > arr[j + 1]:
# 交换元素
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
# 如果在这一轮中没有发生交换,说明数组已经有序
if not swapped:
break
return arr
插入排序
插入排序是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序的思想类似于我们玩扑克牌时,将每张牌插入到已有序的牌中的适当位置。
工作原理:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5,直到所有元素均排序完毕
时间复杂度
最佳: O(n)
平均: O(n²)
最坏: O(n²)
空间复杂度
O(1) - 原地排序
稳定性
稳定排序
插入排序代码实现 (Python)
def insertion_sort(arr):
# 从第二个元素开始,第一个元素默认已排序
for i in range(1, len(arr)):
# 保存当前要插入的元素
key = arr[i]
# 从已排序序列的末尾开始比较
j = i - 1
# 将大于key的元素向后移动一位
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
# 将key插入到正确的位置
arr[j + 1] = key
return arr
选择排序
选择排序是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
以此类推,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。
工作原理:
- 初始状态:整个数组为待排序区域,已排序区域为空
- 从待排序区域中找到最小(或最大)的元素
- 将找到的最小(或最大)元素与待排序区域的第一个元素交换位置
- 此时已排序区域增加一个元素,待排序区域减少一个元素
- 重复步骤2~4,直到待排序区域为空
时间复杂度
最佳: O(n²)
平均: O(n²)
最坏: O(n²)
空间复杂度
O(1) - 原地排序
稳定性
不稳定排序
选择排序代码实现 (Python)
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]
return arr
算法比较
特性 | 冒泡排序 | 插入排序 | 选择排序 |
---|---|---|---|
时间复杂度(最佳) | O(n) | O(n) | O(n²) |
时间复杂度(平均) | O(n²) | O(n²) | O(n²) |
时间复杂度(最坏) | O(n²) | O(n²) | O(n²) |
空间复杂度 | O(1) | O(1) | O(1) |
稳定性 | 稳定 | 稳定 | 不稳定 |
交换次数 | 较多(O(n²)) | 较少(O(n)) | 最少(O(n)) |
比较次数 | O(n²) | O(n²) | O(n²) |
适用场景 | 数据量小且接近有序 | 数据量小且部分有序 | 数据量小,对交换成本敏感 |
如何选择合适的排序算法?
- 当数据基本有序时:优先选择冒泡排序或插入排序,它们在这种情况下性能较好,接近O(n)
- 当数据规模较小时:三种算法均可,但插入排序通常表现更好
- 当交换操作成本较高时:选择排序更有优势,因为它的交换次数最少
- 当需要稳定排序时:避免使用选择排序,优先考虑冒泡排序或插入排序
- 当数据规模较大时:这三种算法都不适合,应考虑快速排序、归并排序等更高效的算法