1. 简单选择排序算法
- 简单选择排序
- 属于选择排序
- 两两比较大小,找出极值(极大值或极小值)被放置在固定的位置,这个固定位置一般指的是某一端
- 结果分为升序和降序排列
- 降序
- n个数从左至右,索引从0开始到n-1,两两依次比较,记录大值索引,此轮所有数比较完毕,将
大数和索引0数交换,如果大数就是索引1,不交换。第二轮,从1开始比较,找到最大值,将它
和索引1位置交换,如果它就在索引1位置则不交换。依次类推,每次左边都会固定下一个大数。
- 升序
2. 简单选择排序演示
初始 | 1 9 8 5 6 7 4 3 2 | |
---|
第一趟 | 9 1 8 5 6 7 4 3 2 | 选择出此轮最大值9,和索引0数交换 |
第二趟 | 9 8 1 5 6 7 4 3 2 | 选择出此轮最大值8,和索引1数交换 |
第三趟 | 9 8 7 5 6 1 4 3 2 | 以此类推 |
第四趟 | 9 8 7 6 5 1 4 3 2 | |
第五趟 | 9 8 7 6 5 1 4 3 2 | |
第六趟 | 9 8 7 6 5 4 1 3 2 | |
第七趟 | 9 8 7 6 5 4 3 1 2 | |
第八趟 | 9 8 7 6 5 4 3 2 1 | |
3. 简单选择排序代码实现(一)*
m_list = [
[1, 9, 8, 5, 6, 7, 4, 3, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[9, 8, 7, 6, 5, 4, 3, 2, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 2]
]
nums = m_list[0]
length = len(nums)
print(nums)
count_swap = 0
count_iter = 0
for i in range(length):
maxindex = i
for j in range(i + 1, length):
count_iter += 1
if nums[maxindex] < nums[j]:
maxindex = j
if i != maxindex:
nums[i], nums[maxindex] = nums[maxindex], nums[i]
count_swap += 1
print(nums, count_swap, count_iter)
4. 简单选择排序代码实现(二)
4.1. 优化实现
- 二元选择排序
- 同时固定左边最大值和右边最小值
- 优点:减少迭代元素的次数
m_list = [
[1, 9, 8, 5, 6, 7, 4, 3, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[9, 8, 7, 6, 5, 4, 3, 2, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 2]
]
nums = m_list[0]
length = len(nums)
print(nums)
count_swap = 0
count_iter = 0
for i in range(length // 2):
maxindex = i
minindex = -i -1
minorigin = minindex
for j in range(i +1, length - i):
count_iter += 1
if nums[maxindex] < nums[j]:
maxindex = j
if nums[minindex] > nums[-j -1]:
minindex = -j -1
if i != maxindex:
nums[i], nums[maxindex] = nums[maxindex], nums[i]
count_swap +=1
if i == minindex or i == length + minindex:
minindex = maxindex
if minorigin != minindex:
nums[minorigin], nums[minindex] = nums[minindex], nums[minorigin]
count_swap += 1
print(nums, count_swap, count_iter)
- 代码解析:
- 1、length//2 整除,通过几次运算就可以发现规律
- 2、由于使用了负索引,所以条件中要增减 i == length + minindex
- 还有没有优化的可能?
4.2. 改进实现
- 如果一轮比较后,极大值,极小值的值相等,说明比较的序列元素全部相等
m_list = [
[1, 9, 8, 5, 6, 7, 4, 3, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[9, 8, 7, 6, 5, 4, 3, 2, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 2]
]
nums = m_list[3]
length = len(nums)
print(nums)
count_swap = 0
count_iter = 0
for i in range(length // 2):
maxindex = i
minindex = -i -1
minorigin = minindex
for j in range(i +1, length - i):
count_iter += 1
if nums[maxindex] < nums[j]:
maxindex = j
if nums[minindex] > nums[-j -1]:
minindex = -j -1
if nums[maxindex] == nums[minindex]:
break
if i != maxindex:
nums[i], nums[maxindex] = nums[maxindex], nums[i]
count_swap +=1
if i == minindex or i == length + minindex:
minindex = maxindex
if minorigin != minindex:
nums[minorigin], nums[minindex] = nums[minindex], nums[minorigin]
count_swap += 1
print(nums, count_swap, count_iter)
4.3. 改进实现
- [1, 1, 1, 1, 1, 1, 1, 1, 2]这种情况,找到的最小索引是-2, 最大值索引8, 上面的代码会交换2次,最小值两个1交换是无用功,所以,增加一个判断
m_list = [
[1, 9, 8, 5, 6, 7, 4, 3, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[9, 8, 7, 6, 5, 4, 3, 2, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 2]
]
nums = m_list[4]
length = len(nums)
print(nums)
count_swap = 0
count_iter = 0
for i in range(length // 2):
maxindex = i
minindex = -i -1
minorigin = minindex
for j in range(i +1, length - i):
count_iter += 1
if nums[maxindex] < nums[j]:
maxindex = j
if nums[minindex] > nums[-j -1]:
minindex = -j -1
if nums[maxindex] == nums[minindex]:
break
if i != maxindex:
nums[i], nums[maxindex] = nums[maxindex], nums[i]
count_swap +=1
if i == minindex or i == length + minindex:
minindex = maxindex
if minorigin != minindex and nums[minorigin] != nums[minindex]:
nums[minorigin], nums[minindex] = nums[minindex], nums[minorigin]
count_swap += 1
print(nums, count_swap, count_iter)
5. 简单选择排序总结
- 简单选择排序需要数据一轮轮比较,并在每一轮中发现极值
- 没有办法知道当前轮是否已经达到排序要求,但是可以知道极值是否在目标索引位置上
- 遍历次数1,…,n-1之和n(n-1)/2
- 时间复杂度O(n2)
- 减少了交换次数,提高了效率,性能略好于冒泡法