1.冒泡排序
def bubble_sort(lst):
for i in range(1,len(lst)): # 第n次循环找到排序后第len(lst)-n+1个位置的值【相对最大值】
for j in range(0, len(lst)-i):
if lst[j] > lst[j+1]:
lst[j+1], lst[j] = lst[j], lst[j+1]
return lst
print(bubble_sort([0, 5, 2, 1]))
2.选择排序
# 方式:找到len(lst)个相对最小值(两层for循环实现)。
def select_sort(lst):
for i in range(len(lst) - 1): # 第n次循环找到排序后第n个位置的值【相对最小值】
for j in range(i + 1, len(lst)):
if lst[j] < lst[i]:
lst[i], lst[j] = lst[j], lst[i]
return lst
print(select_sort([0, 5, 2, 1]))
1-2.冒泡排序与选择排序的区别
- 冒泡排序每次外循环结束后,得到一个排序后的最大值。【向左推进】
- 选择排序每次外循环结束后,得到一个排序后的最小值。【向右推进】
排序方式/ 性质 | 时间复杂度 | 空间复杂度 | 最好情况 | 最坏情况 | 稳定排序 | 原地排序 |
---|---|---|---|---|---|---|
冒泡排序 | O(n2) | O(1) | O(n) | O(n2) | 稳定 | 是 |
选择排序 | O(n2) | O(1) | O(n2) | O(n2) | 不稳定 | 是 |
3.插入排序
简要描述:插入排序过程类似于打扑克时的 理牌 过程。
过程简单描述:
- 1:循环,从数组第2个元素开始遍历
- 1.1:循环,找到插入位置(把它与它位置左边的元素做比较)
- 1.2:循环,腾出插入位置(保存当前需要插入的元素后,使原本插入位置至当前插入元素位置的前一个元素都往后移动一位)
- 1.3:插入元素至插入位置
def insert_sort(lst):
# 循环第r次后,前r+1个元素都是有序的。
for i in range(1,len(lst)):
insert_ele = lst[i]
insert_index = i
# 1.找到插入的位置
for j in range(i-1, -1,-1):
if lst[i] < lst[j]:
insert_index = j
else:
break
# 2.腾出位置给要插入的元素
for move in range(i-1,insert_index-1,-1):
lst[move+1] = lst[move]
# 3.插入元素
lst[insert_index] = insert_ele
return lst
print(insert_sort([0, 5, 2, 1]))
4.希尔排序
简要描述:是插入排序的变种,多次分组 + 组内插入排序。
过程简单描述:
- 1:循环,多次分组。
- 1.2:循环,在当前分组情况下,对各元素排序。
各分组都从相对第2个元素开始(gap)元素进行插入排序。 - 1.2.1:循环,找到插入位置(把它与它位置左边的元素做比较,注意增量为 -gap)
- 1.2.2:循环,腾出插入位置
- 1.2.3:插入元素至插入位置
def shell_sort(lst):
import math
gap = math.floor(len(lst)/2)
while gap>=1:
# 当前分组情况下,对所有组内元素一起插入排序(每个元素在所属组内插入排序)。
for i in range(gap,len(lst),1):
insert_item(lst,gap,i)
gap = math.floor(gap/2)
return lst
# 各组内排序,增量为gap。组内元素为i-k*gap
def insert_item(lst,gap,i):
insert_ele = lst[i]
insert_index = i
for j in range(i-gap, -gap, -gap):
if lst[i] < lst[j]:
insert_index = j
else:
break
for move in range(i - gap, insert_index - gap, -gap):
lst[move + gap] = lst[move]
lst[insert_index] = insert_ele
print(shell_sort([0, 5, 2, 1]))
3-4.插入排序和希尔排序比较
排序方式/ 性质 | 时间复杂度 | 空间复杂度 | 稳定排序 | 原地排序 |
---|---|---|---|---|
插入排序 | O(n2) | O(1) | 是 | 是 |
希尔排序 | O(nlogn) | O(1) | 否 | 是 |
5.归并排序
基本思想
通过递归的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的 …… 直到全部小的数组合并起来。
过程简单描述
- 1.分:将大的数组一直二分,直到数组的大小为1时结束分割。
- 2.递归治:将左侧数组排成有序。
- 3.递归治:将右侧数组排成有序。
- 4.合:将左侧有序数组与右侧有序数组合并成一个新的有序数组。
代码实现
import math
def merge_sort(lst, left, right):
# 二分至只有一个元素时结束递归分治
if left < right:
center = math.floor((right + left) / 2) # 1.分
merge_sort(lst, left, center) # 2.治,结束后左侧数组有序
merge_sort(lst, center + 1, right) # 3.治,结束后右侧数组有序
merge(lst, left, center, right) # 4.合,将左右两数组合并
def merge(lst, left, center, right):
pointer_left = left # 左侧数组指针
pointer_right = center + 1 # 右侧数组指针
temp = lst.copy() # 遍历时修改数组,借用第三者
for index in range(left, right + 1):
if pointer_left > center: # 左边元素全部合并完,剩下有序的右边元素数组赋值即可。
temp[index:right + 1] = lst[pointer_right:right + 1]
break
elif pointer_right > right: # 右边元素全部合并完,剩下有序的左边元素数组赋值即可。
temp[index:right + 1] = lst[pointer_left:center + 1]
break
# 下面两个case是取两侧数组中最小的元素放入临时数组中,取完后对应指针后移1
elif lst[pointer_left] < lst[pointer_right]:
temp[index] = lst[pointer_left]
pointer_left += 1
else:
temp[index] = lst[pointer_right]
pointer_right += 1
lst[:] = temp[:] # 将排序好的临时数组赋给lst。
lst = [0, 5, 2, 1, 7, 0, 9, 3, 4, 8]
merge_sort(lst, 0, len(lst) - 1)
print(lst)
性质
排序方式/ 性质 | 时间复杂度 | 空间复杂度 | 稳定排序 | 原地排序 |
---|---|---|---|---|
归并排序 | O(nlogn) | O(n) | 稳定 | 否 |
6.快速排序
基本思想(分治法+挖坑填数):
- 先从数列中取出一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数。
代码实现
# 调整序列(选定基准数,把比基准数小的放在基准数的左边,把比基准数大的放在基准数的右边)
def list_adjust(lst, index_left, index_right):
pointer_left = index_left
pointer_right = index_right
refer_num = lst[index_left] # 选定基准数(并且“挖了一个坑”)
# 一次循环包括:从右向左前进直到填坑一次,从左向右前进直到填坑一次。
while pointer_left < pointer_right:
# 坑在左侧,从右侧开始向左前进,直到右侧数字小于基准数则填坑,坑转移到右侧。
while pointer_left < pointer_right and lst[pointer_right] >= refer_num:
pointer_right -= 1
if pointer_left < pointer_right:
lst[pointer_left] = lst[pointer_right] # 用右侧替换左侧
# 坑在右侧,从左侧开始向右前进,直到左侧数字大于基准数则填坑,坑转移到左侧。
while pointer_left < pointer_right and lst[pointer_left] < refer_num:
pointer_left += 1
if pointer_left < pointer_right:
lst[pointer_right] = lst[pointer_left] # 用左侧替换右侧
lst[pointer_left] = refer_num # 循环结束,填剩下的左侧坑(其实pointer_left=pointer_right,重合不分左右了)
return pointer_left
# 分治法
def quick_sort(lst, index_left, index_right):
if index_left < index_right:
mid = list_adjust(lst, index_left, index_right)
quick_sort(lst, index_left, mid - 1) # 递归对左侧排序
quick_sort(lst, mid + 1, index_right) # 递归对右侧排序
if __name__ == '__main__':
lst = [4, 5, 1, 2, 9]
quick_sort(lst, 0, 4)
print(lst)
来源:CSDN
作者:iamjwe
链接:https://blog.csdn.net/jw2268136570/article/details/103798497