算法--排序
#堆排
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)