排序方法指的是对一个无序的数列,按照一定方法让其变得有序。排序法重点是思维过程,本文中的四种排序方法都较为基础,但其中蕴含的算法思维各不相同,适合作为算法入门学习内容。
- 选择排序法
我认为选择排序法是较符合一般人思维模式的排序法,它是指对于每个数列,从其中找出最小的一个数字,将其放至首位,然后再不断对剩余的无序数列重复此操作。当剩余无序数列的长度为0时,则完成排序。其python实现代码如下:
点击查看代码
def select_sort(my_list):
n= len(my_list) # n为数列长度
for i in range(n-1): # 共进行n-1次选择(外循环),因为只要选出最小的n-1个数,最大的数就是剩下的,不需要进行额外操作天然已经位于数列末端
min_i = i # 初始化最小数字的索引为无序数列的第一个元素的索引,即假设第一个数字现在就是最小值。
for j in range(i+1,n): # 内循环处理无序数列中的每一个元素
if my_list[j]<my_list[min_i]: #一旦无序数列中的数字比我们假设的初始值小,就将其索引记录下来
min_i = j
if min_i != i: # 一次内循环完成后,已经将无序数列中最小值的索引赋值给了min_i,如果其不同于无序数列的最左端(第一个)数字,则将两者交换。交换完成后最小值已位于无序数列的最左段,此时可以将其视为有序数列的最右端,而不再是无序数列的一部分(通过外循环i的不断增加来实现)
my_list[i],my_list[min_i] = my_list[min_i],my_list[i]
- 冒泡排序法
冒泡排序的过程是每次将最大的一个元素放至队列末尾,这听起来很像选择排序的反过程。但是冒泡排序的实现是完全不同的。每一次排序,都是将无序数列的每一位,依次与其右边的元素进行比较,并将其中较大的数字放在右边。如此操作,大的数字会不断被向右移,直至遇到比他更大的数字。这个更大的数字会接过其接力棒,再次向右进行比较,直到到达无序数列的最后一位。代码实现如下:
点击查看代码
def bubble_sort(my_list):
listlen = len(my_list)
for i in range(listlen-1): # i 代表轮次,范围为0到n-2共n-1次(最大的n-1个数字排完无需再排第n个)
for j in range(listlen-1-i): # j 为每轮进行比较的第一个数字,因为最后的i个数字已经完成了排序,所以每次都是比较(n-1)-i个数字即可。对于第一轮
if my_list[j]>my_list[j+1]: # 如果比右边数字大,则进行交换
my_list[j],my_list[j+1]=my_list[j+1],my_list[j]
- 插入排序
插入排序是指将每个序列分为左右两个部分,左边是已经从小到大排序完成的数列,右边是无序数列,依次将无序数列的第一位插入至有序数列中。对于一个未经过排序的数列,可以将第一个数字视作有序的(很显然单独一个数字必然是有序的),而将第二个数字开始的剩余数字视为需要排序的无序数列。代码实现如下:
点击查看代码
def insert_sort(my_list):
n = my_list
for i in range(1,n): # i 表示现在要处理第i个数字(第0)位不需要处理,在处理完这n-1个数字后它会天然出现在应该出现的位置
for j in range(i+1,0,-1): # j 指示要进行比较的数字,每次与左边的数字进行比较,如果小于左边数字说明应该左移
if my_list[j]<my_list[j-1]:
my_list[j],my_list[j-1] = my_list[j-1],my_list[j]
else:
break
- 快速排序
快速排序的逻辑很简单,但是代码实现会稍微复杂一点。原理是:随便选取一个数字,将数列中比其小的数字都放到它左侧,比它大的数字都放在它右侧,以此来确定其在数列中的位置;之后,再对于每个没有确定下来的数列区间重复此操作,直至每个数字都位于正确的位置。快排使用了递归的方式去排序,代码实现如下:
点击查看代码
def quick_sort(my_list,start,end):
"""
快速排序
:param my_list: 要排序的列表
:param start: 表示从哪个位置开始排序
:param end: 表示到哪个位置结束排序
:return: 如果start>=end,则表示排序完成,否则需要继续排序
"""
if start >=end: # 当一个区间的长度为1或0时,说明已经排好序,则直接返回
return
left = start #左指针为区间的第一个元素
right = end #右指针
mid = my_list[start] # 选取第一个元素作为中间值(基准值)。此时左指针位置空出来了
while left < right: # 左右指针向中间移动,直到左右指针相遇
while my_list[right]>=my_list and left <right: # 右指针向左移动,直到遇到小于等于基准值的元素
right-=1
my_list[left] = my_list[right] # 将小于等于基准值的元素放到左指针位置
while my_list[left]<my_list and left <right: # 左指针向右移动,直到遇到大于等于基准值的元素
left+=1
my_list[right] = my_list[left] # 将大于等于基准值的元素放到右指针位置
my_list[left] = mid # 经过上述的两次交换之后,可能存在两种情况:1.左右指针相遇;2.左指针的值已经赋给了右指针的位置。无论哪种情况,都需要将基准值放到左指针的位置。
# 递归左半区间。如果 start=left-1,说明这次排序完之后左半区只有一个元素,不需要再排序。如果start>left-1,说明左半区为空,不需要再排序。
quick_sort(my_list,start,left-1)
quick_sort(my_list,right+1,end) # 递归右半区间