原理:
第一步:
将乱序中的最大值找出,逐一移到序列最后的位置
alist = [3, 5, 9, 2, 1, 7, 8, 6, 4] def bubble_sort(alist): # 找最大值的方式是通过对列表中的元素进行两两比较,值大的元素逐步向后移动 # 序列中有n个元素,两两比较的话,需要比较n-1次 for i in range(len(alist) - 1): # 循环n-1次,控制两两比较的次数 if alist[i] > alist[i + 1]: # 如果前面的元素大于后面的元素,交换两个元素的位置,否则不做任何操作 alist[i], alist[i + 1] = alist[i + 1], alist[i] return alist print(bubble_sort(alist)) # 输出:最大值已经移动到最右边了 [3, 5, 2, 1, 6, 7, 8, 4, 9]
当上述代码已经可以将序列中的最大值放置到合适的位置,然后我们就可以将上述操作继续作用到 n-1 和元素对应的新序列,则就可以将 n-1 个元素对应的最大值放置到了 n-1 和元素的最后位置。
结论:发现如果将上述的操作逐步的作用 n-1 此就可以将整个序列变成有序的。
第二步:
将第一步的操作继续作用 n-1 次
alist = [3, 5, 9, 2, 1, 7, 8, 6, 4] def bubble_sort(alist): for j in range(len(alist)-1): # 外层循环次数递增,内层循环次数递减 for i in range(len(alist) - 1-j): # 循环次数需要递减-j,控制两两比较的次数 if alist[i] > alist[i + 1]: # 如果前面的元素大于后面的元素,交换两个元素的位置,否则不做任何操作 alist[i], alist[i + 1] = alist[i + 1], alist[i] return alist print(bubble_sort(alist)) # 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9]
思路:
第一步:
将乱序中的元素两两比较,找出最大值,然后直接将最大值放置到序列最后的位置(将最大值直接和最后一个元素交换位置)
def select_sort(alist): max_index = 0 # 最大值元素的下标,一开始假设下标为0的元素为最大值 for i in range(len(alist) - 1): # 循环控制两两比较的次数 # 如果在比较的过程中发现,下标为max_index不是最大值,那么就改变max_index if alist[max_index] < alist[i + 1]: max_index = i + 1 # 循环结束后max_index就一定是最大值的下标,并且把该数和最后一个值做交换 alist[len(alist) - 1], alist[max_index] = alist[max_index], alist[len(alist) - 1] return alist alist = [3, 5, 9, 2, 1, 7, 8, 6, 4] print(select_sort(alist)) # 输出 [3, 5, 4, 2, 1, 7, 8, 6, 9]
第二步:
将第一步继续作用 n-1 次
def select_sort(alist): for j in range(len(alist) - 1):# 外层循环递增n-1次 max_index = 0 # 最大值元素的下标,一开始假设下标为0的元素为最大值 for i in range(len(alist) - 1 - j): # 内层循环递减,循环控制两两比较的次数 # 如果在比较的过程中发现,下标为max_index不是最大值,那么就改变max_index if alist[max_index] < alist[i + 1]: max_index = i + 1 # 循环结束后max_index就一定是最大值的下标,并且把该数和最后一个值做交换 alist[len(alist) - 1 - j], alist[max_index] = alist[max_index], alist[len(alist) - 1 - j] return alist alist = [3, 5, 9, 2, 1, 7, 8, 6, 4] print(select_sort(alist))
思路:
注意:初始情况下,有序部分为乱序序列中的第一个元素,无序部分为乱序序列的 n-1 个元素
例如:
# 乱序序列:[8,3,5,7,6] [8, 3,5,7,6] # 8就是初始的有序部分,3、5、7、6就是初始的无序部分 [3,8, 5,7,6] [3,5,8, 7,6] [3,5,7,8, 6] [3,5,7,6,8, ]
第一步:
定义一个变量 i ,i 表示的是有序部分元素的个数和无序部分第一个元素小标
alist = [8, 3, 1, 6, 7] i = 1 # i 就是有序部分元素的个数和无序部分第一个元素下标 # alist[i-1]:有序部分最后一个元素下标 # alist[i]:无序部分第一个元素下标 if alist[i - 1] > alist[i]: alist[i], alist[i - 1] = alist[i - 1], alist[i] # [3, 8, 1, 6, 7]
第二步:循环作用到每个元素中
alist = [8, 3, 1, 6, 7] i = 2 # alist[i-1]:有序部分最后一个元素下标 # alist[i]:无序部分第一个元素下标 while i > 0: if alist[i - 1] > alist[i]: # 循环第一次时[3,1,8, 6,7] alist[i], alist[i - 1] = alist[i - 1], alist[i] i -= 1 # 循环继续 # [1,3,8, 6,7] else: break
第三步:
处理变量 i,需要让 i 进行自己递增
for i in range(1, len(alist)): # i = [1,2,3,4] # alist[i-1]:有序部分最后一个元素下标 # alist[i]:无序部分第一个元素下标 while i > 0: if alist[i - 1] > alist[i]: alist[i], alist[i - 1] = alist[i - 1], alist[i] i -= 1 else: break
完整代码:
def insert_sort(alist): for i in range(1, len(alist)): while i > 0: if alist[i - 1] > alist[i]: alist[i - 1], alist[i] = alist[i], alist[i - 1] i -= 1 else: break return alist
关键变量:增量gap
gap:初始值为 len(alist) // 2
插入排序就是增量为 1 的希尔排序
第一步:
将插入排序代码写出
def hill_sort(alist): for i in range(1, len(alist)): while i > 0: if alist[i - 1] > alist[i]: alist[i - 1], alist[i] = alist[i], alist[i - 1] i -= 1 else: break return alist
第二步:
在插入排序代码中加入增量的概念
def hill_sort(alist): gap = len(alist) // 2 # 初识增量 # 将插入排序中的增量1替换成gap # 由增量1变成了增量为gap了 for i in range(gap, len(alist)): while i > 0: if alist[i - gap] > alist[i]: alist[i - gap], alist[i] = alist[i], alist[i - gap] i -= gap else: break return alist
第三步:
在第二步中进行增量的缩减(增量缩减到1结束)完整代码
def hill_sort(alist): gap = len(alist) // 2 # 初识增量 while gap >= 1: for i in range(gap, len(alist)): while i > 0: if alist[i - gap] > alist[i]: alist[i - gap], alist[i] = alist[i], alist[i - gap] i -= gap else: break gap //= 2 # 缩减增量 return alist
思路:
第一步:
核心操作,将基数 mid 放置到序列中间,使得基数左侧都是比它小的,右侧是比它大的
def quick_sort(alist): low = 0 # 第一个元素下标 high = len(alist) - 1 # 最后一个元素下标 mid = alist[low] # 基数:初始值为序列中的第一个数值 while low != high: # 先移动high while low < high: if mid < alist[high]: # 下标high对应的值大于mid,high就向右偏移1 high = high - 1 else: # 否则,就把将high指向的数值放置到左侧下标为low对应的空位 alist[low] = alist[high] break # 传递后high下标偏移结束 # 开始移动low while low < high: if mid > alist[low]: # 下标low对应的值小于mid,low就向左偏移1 low = low + 1 else: # 否则,就把将low指向的数值放置到左侧下标为high对应的空位 alist[high] = alist[low] break # 并结束 # 最后当low和high相等的时候,那么就把mid传给下标为low或high的位置 alist[low] = mid return alist alist = [6, 1, 2, 7, 9, 3, 4, 5, 10, 8] print(quick_sort(alist)) # 输出——>6左边都是比6小的,右边都是比6大的 [5, 1, 2, 4, 3, 6, 9, 7, 10, 8]
第二步:
将第一步的核心操作递归作用到基数的左右两侧的子序列中
# 那么如何区分根据基数拆分出的左右子序列呢?可以通过传入指定的left和right来指定不同的子序列 def quick_sort(alist, left, right): low = left # 第一个元素下标 high = right # 最后一个元素下标 if low > high: # 递归结束条件,low是不能大于high的 return mid = alist[low] # 基数:初始值为序列中的第一个数值 while low != high: # 先移动high while low < high: if mid < alist[high]: # 下标high对应的值大于mid,high就向右偏移1 high -= 1 else: # 否则,就把将high指向的数值放置到左侧下标为low对应的空位 alist[low] = alist[high] break # 传递后high下标偏移结束 # 开始移动low while low < high: if mid >= alist[low]: # 下标low对应的值小于mid,low就向左偏移1 low += 1 else: # 否则,就把将low指向的数值放置到左侧下标为high对应的空位 alist[high] = alist[low] break # 并结束 # 最后当low和high相等的时候,那么就把mid传给下标为low或high的位置 if low == high: alist[low] = mid # 上述为核心操作,需要将核心操作递归作用到左右子序列中 quick_sort(alist, left, low - 1) # 递归到左侧序列中 quick_sort(alist, high + 1, right) # 递归到右侧序列中 return alist alist = [6, 1, 2, 7, 9, 3, 4, 5, 10, 8] print(quick_sort(alist, 0, len(alist) - 1)) # 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]