#堆排
def sift(li, low, high):
'''
:param li:树
:param low: 树的根节点
:param high: 树的最后一个节点
:return:向下调整树
'''
tmp = li[low] # 去除树根作为临时变量
i = low # i指向空位
j = 2 * i + 1 # 第一次 j指向根节点的左孩子
while j <= high: # 循环继续的条件:j不越界;This the second end condition:j越界
# 1.比较左右子节点
if j + 1 <= high and li[j] < li[j + 1]: # 右节点存在,才进行左右比较
j += 1 # 将j指向j+1
if li[j] > tmp: # 调整位置
li[i] = li[j] # 空位的元素填成j下标的元素,所谓的调整
i = j # 向下调整
j = 2 * j + 1 # 从当前j节点找左孩子
else:
break # j位置的元素>tmp 停止循环,This the first end condition
li[i] = tmp # 结束循环,空位填充tmp
#堆排
def heak_sort(li):
n = len(li)
# 1.构造堆
for low in range((n - 2) // 2, -1, -1): # 根据子节点找父节点i-->(i-1)//2
sift(li, low, n - 1)
print(li)
# 2.挨个出数
for high in range(n - 1, -1, -1):
li[0], li[high] = li[high], li[0]
sift(li, 0, high - 1) # 排除堆中的最后一个元素
li = [8, 1, 2, 6, 3, 7]
heak_sort(li)
print(li) # [1, 2, 3, 6, 7, 8]
#冒泡排序 时间复杂度O(n*n)
def bubble_sort(li):
for i in range(len(li)): # 表示躺数n躺
flag = False
for j in range(len(li) - 1 - i): # 表示第n躺无序区的范围 0--n-i-1
if li[j] > li[j + 1]:
li[j], li[j + 1] = li[j + 1], li[j]
flag = True
if not flag: # 表示无序区已经有序
break
return li
# 选择排序
'''思路:选择一个最小的val,和无序区的第一个元素进行,交换.时间复杂度O(n*n)'''
def select_sort(li):
for i in range(len(li)):
min_pos = i
for j in range(i + 1, len(li)):
if li[j] < li[min_pos]:
min_pos = j # 更新最小值的下标
li[i], li[min_pos] = li[min_pos], li[i]
return li
# 插入排序
'''思路:选择一个数,和有序区的元素进行比较,如果小于有序区的元素,就将每一个元素向后挪(1.比较的下标<0;2.比较的数>选择的数),依次比较最后插入位置'''
def insert_sort(li):
for i in range(1, len(li)): # 无序区的范围
tmp = li[i] # 默认取无序区的第一个元素和前面的每个元素进行比较
j = i - 1 # 有序区的最后一个元素下标
while j >= 0 and li[j] > tmp: # ***必须是j>=0 and li[j]>tmp 否则li[-1]会error
li[j + 1] = li[j] # 向后挪
j -= 1 # 向前找一个
li[j + 1] = tmp # 找到符合条件的下标j,后面一个空位即tmp的位置
return li
# 快速排序
def quick_sort(li, left, right):
'''nlogn'''
if left < right:
# 归为元素下标
mid = partition(li, left, right) # 归位
quick_sort(li, left, mid - 1) # 排 mid 左边的元素
quick_sort(li, mid + 1, right) # 排mid右边元素
return li
def partition(li, left, right):
'''O(n)'''
tmp = li[left]
while left < right: # 排序区至少有2个元素
while left < right and li[right] > tmp: # 从右边往左走,
# if left == right:
# break
right -= 1
li[left] = li[right] # 丢到左边
while left < right and li[left] < tmp: # left=3 越界 此时li[2]=li[3]
# if left == right:
# break
left += 1 # 加等完事儿后注意越界问题,left!!!
li[right] = li[left] # 丢到右边 越界导致问题----
# 退出循环left == right ==mid
li[left] = tmp # 丢到右边 越界导致问题---- li[3]=tmp 导致【1,2,4,3,5】
return left
print(quick_sort([2,1,4,3,5],0,4))
# 归并排序.:先分解在merge
# 归并:时间复杂度O(n);空间复杂度O(n) 条件:一个列表中前后部分是有序的的[2,5,7,8,9,1,3,4,6,]
def merge(li, low, mid, high):
"""
思路:分别比较两段列表的每个元素的位置,如果谁小,谁添加进li_tmp;最后两边的列表会剩下,依次循环append即可
:param li:排序的列表
:param low: 开始的位置
:param mid: 有序的分段的位置
:param high: 结尾的位置
:return:
"""
li_tmp = []
i = low
j = mid + 1
while i <= mid and j <= high: # 考虑 = 的情况,最后j+1后 j=8;所有必须<=防止少
if li[i] < li[j]:
li_tmp.append(li[i])
i += 1
if li[j] < li[i]:
li_tmp.append(li[j])
j += 1
# 剩下的元素
while i <= mid:
li_tmp.append(li[i])
i += 1
while j <= high:
li_tmp.append(li[j])
j += 1
li[low:high + 1] = li_tmp
return li
# 归并排序O(nlog(n))
def merge_sort(li, low, high):
if low < high:
mid = (low + high) // 2
# print(li[low: mid + 1], li[mid + 1: high])
# 分解左边
merge_sort(li, low, mid)
# 分解右边
merge_sort(li, mid + 1, high)
# print(li[low: mid + 1], li[mid + 1: high])
# 归并
merge(li, low, mid, high)
print(li[low: mid + 1], li[mid + 1: high])
li = [2, 5, 7, 8, 9, 1, 3, 4, 6]
merge_sort(li, 0, 8)
print(li)