选择排序
原理
# 循环列表,每次循环找到列表中的最小数,放到一个位置上;
# 再次循环找到剩下列表中的最小数,放在之前找到的最小数下一个位置。
代码实现
初步实现思路
# 循环列表,找到列表中的最小数,将这个最小数从原列表中取出后放入一个空的新列表中;
# 不过这种实现思路会导致同时存在两个列表,空间复杂度较高
初步实现代码
# -*- coding: utf-8 -*-
# created by X. Liu on 2020/3/8
def select_sort_simple(li):
new_li = []
for _ in range(len(li)): # 循环中不实用循环次数的值,故使用占位符 _
min_val = min(li) # min()函数是一个O(n)的循环操作
new_li.append(min_val)
li.remove(min_val) # remove()函数也是一个O(n)的循环操作
return new_li # 整个算法的时间复杂度是O(n^2),空间复杂度O(n)
升级版思路
# 上述代码实现是通过一个新列表实现位的,但是会导致占用额外的内存空间
# 参考冒泡排序的原地交换思路,实现原地交换的选择排序
# 首先默认min_index等于无序区第一个位置,如果后面位置上的数比默认位置上的数小,即重置最小数的位置,
# 这样每趟循环后,min_index都是无序区最小数的位置。
# 将无序区第一个位置的数和min_index上的数交换,实现原地交换
升级版代码
def select_sort(li):
for i in range(len(li) - 1): # i表示循环趟数
min_index = i # 默认无序区的第一个位置上的元素最小,最为比较的参考对象
for j in range(i+1, len(li)): # j比较的起始位置,可以从i+1开始,减少一次和自己比较的循环
if li[j] < li[min_index]:
min_index = j # 记录最小数的位置
# 一趟循环后,找到无序区最小数的位置,交换无序区第一个位置的数和无序区最小的数
li[i], li[min_index] = li[min_index], li[i]
动画演示
补充思考
def select_sort(li):
for i in range(len(li) - 1):
min_index = i
for j in range(i+1, len(li)):
if li[j] < li[min_index]:
min_index = j
li[i], li[min_index] = li[min_index], li[i]
# 上述实现思路和代码已经很简洁明了啦。但是在选择比较的过程中,我们是基于位置实现的:
# 也就是说,通过比较数据大小,记录最小数的所在的位置。
# 每趟循环后拿最小数所在的位置,交换两个
# 个人认为这样很好但是不是非常好理解。最简单的理解应该是比较大小后,直接交换两个数
def select_sort_v2(li):
for i in range(len(li) - 1):
# min_val = li[i]
for j in range(i + 1, len(li)):
if li[j] < li[i]: # 默认w无序区第一个数是最小的
li[j], li[i] = li[i], li[j]
# 值得注意的是这样最然在思路和代码上看起来更容易理解,但是它也有一个不足:
# 不足在于它每趟循环内,在比较的过程中多次交换数据。在性能上不如select_sort()的一次交换