选择排序法:
两两比较大小,找出极值(极大值或极小值),放在固定的位置,这个固定的位置一般指的是某一端
降序排列:
- n个数从左至右,索引从0开始到n-1,第一轮开始,假设索引0为最大数的索引,与后面的数两两依次比较,记录较大数的索引,此轮所有数比较完毕,将较大数的索引和索引0的数交换,如果大数位置就在索引0,不交换。第一轮比较完成后,位于索引0的数为最大值。
- 第二轮,从索引1开始,与后面的数进行比较,找到剩余数中的最大数,将它与索引1的数交换,如果它就在索引1,则不交换。以此类推,每次左边都会固定下一个大数。
选择排序算法代码:
#选择排序法
nums=[1,2,7,3,4,5]
print("待排序的数列:",nums)
count_swap=0
count_iter=0
for i in range(len(nums)-1):
max_index=i #每轮循环初始化最大值的索引
for j in range(i+1,len(nums)):
count_iter+=1
print("第{}轮:索引{}和索引{}比较,".format(i+1,max_index,j),end=" ")
if nums[max_index]<nums[j]:
max_index=j
print("较大值的索引为 {}".format(max_index))
if i!=max_index:
tem=nums[i]
nums[i]=nums[max_index]
nums[max_index]=tem
count_swap+=1
print("第{}轮比较后的排序结果为:{}".format(i+1,nums))
print("排序后的结果为:{},总迭代次数为:{}次,总交换次数为:{}次".format(nums,count_iter,count_swap))
运行结果:
算法优化:
上述算法中,每一轮循环时,只找出了最大值,因此可以在一轮循环中,同时找出最大值和最小值,分别放在左右两端,此方法可以减少迭代次数。
优化算法代码:
#选择排序法优化
nums=[1,2,7,3,4,5]
print("待排序的数列:",nums)
count_swap=0
count_iter=0
for i in range(len(nums)//2):
max_index=i #每轮循环初始化最大值索引
min_index=-i-1 #初始化最大值索引
min_index=-i-1 #初始化最小值索引
min_origin=min_index #初始化最小值索引
for j in range(i+1,len(nums)-i):
count_iter+=1
print("第{}轮:索引{}和索引{}比较,".format(i+1,max_index,j),end=" ")
if nums[max_index]<nums[j]:
max_index=j
print("较大值的索引为 {}".format(max_index),end=" ")
print("; 索引{}和索引{}比较,".format(min_index,-j-1),end=" ")
if nums[min_index]>nums[-j-1]:
min_index=-j-1
print("较小值的索引为 {}".format(min_index))
if i!=max_index:
tem=nums[i]
nums[i]=nums[max_index]
nums[max_index]=tem
count_swap+=1
#如果最小值被替换,则要更新索引
if i==min_index or i==len(nums)+min_index:
min_index=max_index
if min_origin != min_index:
tmp=nums[min_origin]
nums[min_origin]=nums[min_index]
nums[min_index]=tmp
count_swap+=1
print("第{}轮比较后的排序结果为:{}".format(i+1,nums))
print("排序后的结果为:{},总迭代次数为:{}次,总交换次数为:{}次".format(nums,count_iter,count_swap))
运行结果:
算法总结:
- 选择排序需要数据一轮轮比较,并在每一轮中发现极值
- 没有办法知道当前轮是否已经达到排序要求,但是可以知道极值是否在目标索引位置上
- 遍历次数为1,2,…n-1之和n(n-1)/2
- 时间复杂度为O(n**2)
- 减少了交换次数,提高了效率,性能略好于冒泡排序法