一、排序 Low B三人组
1.1 冒泡
思想:
1> 每两个相邻的数,如果前面比后面大,则交换这两个数。
2> 一趟排序完成后,则无序区减少一个数,有序区增加一个数。
3> 代码关键点:趟、无序区范围
代码:
def bubble_sort(li):
for i in range(len(li)-1):
for j in range(len(li)-1-i):
if li[j] > li[j+1]:
li[j], li[j+1] = li[j+1], li[j]
改进,某一趟未交换则表示排序完成
def bubble_sort(li):
for i in range(len(li)-1):
exchage = False
for j in range(len(li)-1-i):
if li[j] > li[j+1]:
li[j], li[j+1] = li[j+1], li[j]
exchage = True
if not exchage:
return li
return li
时间复杂度:
O(n2)。
它是一种稳定的排序算法。(稳定是指如果数组里两个相等的数,那么排序前后这两个相等的数的相对位置保持不变。)
1.2 选择
思想:
1> 一趟排序记录最小的数,放到第一个位置
2> 再一趟排序记录列表无序区最小的数,放到第二个位置
3> ……
4> 算法关键点:有序区和无序区、无序区最小数的位置
代码:
def select_sort(li):
for i in range(len(li)-1): # i是第几趟
min_loc = i
for j in range(i+1, len(li)):
if li[j] < li[min_loc]:
min_loc = j
li[i], li[min_loc] = li[min_loc], li[i]
return li
1.3 插入
思想:
1> 初始时⼿手⾥里里(有序区)只有⼀一张牌
2> 每次(从⽆无序区)摸⼀一张牌,插⼊入到⼿手⾥里里已 有牌的正确位
代码:
def insert_sort(li):
for i in range(1, len(li)):
tmp = li[i] # 拿出i位置,空出来
j = i - 1
while j >= 0 and li[j] > tmp:
li[j+1] = li[j] # 填补空位
j -= 1 # 下标左移
li[j+1] = tmp # 将i位置的值放在j+1
return li
二、排序 NB 三人组
2.1 快排
思想:
1> 取一个元素p(第一个元素),使元素p归位;
2> 列表被p分成两部分,左边都比p小,右边都比p大;
3> 递归完成排序。
def partion(data, left, right):
tmp = data[left]
while left < right:
while left < right and data[right] >= tmp:
right -= 1
data[left] = data[right]
while left < right and data[left] <= tmp:
left += 1
data[right] = data[left]
data[left] = tmp
return left
def quick_sort(data, left, right):
if left < right:
mid = partion(data, left, right)
quick_sort(data, left, mid-1)
quick_sort(data, mid+1, right)
2.2 归并
思想
一开始先把列表从中间划分成两个子列表,一直递归地把列表组划分成更小的子列表,直到子列表里面只有一个元素,才开始排序。
排序的方法就是按照大小顺序合并两个列表,接着依次按照递归的返回顺序,不断地合并排好序的子列表,直到最后把整个列表的顺序排好。
代码
def merge(li, low, mid, high): # (low,mid) (mid+1,high)
i = low
j = mid + 1
ltmp = []
while i <= mid and j <= high: # 左右两边都有数
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
# while执行完,有一边没数
while i <= mid:
ltmp.append(li[i])
i += 1
while j <= high:
ltmp.append(li[j])
j += 1
li[low:high+1] = ltmp
def merge_sort(li, low, high):
if low < high: # 至少有两个元素,递归
mid = (low + high) //2
merge_sort(li, low, mid)
merge_sort(li, mid+1, high)
merge(li, low, mid, high)
2.3 堆排
思想
1.建⽴立堆。
2.得到堆顶元素,为最⼤大元素
3.去掉堆顶,将堆最后⼀一个元素放到堆顶,此时可通过⼀一次调整重新使堆有序。
4.堆顶元素为第⼆二⼤大元素。
5.重复步骤3,直到堆变空
代码
def sift(li, low, high): # 调整
i = low # i最开始指向根节点,父亲层
j = 2 * i + 1 # j开始是左孩子
tmp = li[low] # 把堆顶存起来
while j <= high: # 只要j位置有数
if j + 1 <= high and li[j + 1] > li[j]: # 如果右孩子有且比较大
j = j + 1 # j指向右孩子
if li[j] > tmp:
li[i] = li[j]
i = j # 往下看一层
j = 2 * i + 1
else: # tmp更大,把tmp放到i位置上
li[i] = tmp
break
else:
li[i] = tmp # 把tmp放到叶子节点上
def heap_sort(li):
n = len(li)
for i in range((n - 2) // 2, -1, -1): # 子找父 (i-1)//2, (n-1 -1)//2, n//2 -1, 遍历到0不包括-1
# i表示建堆的时候调整的部分的根的下标
sift(li, i, n - 1)
# 建堆完成
print("建堆完成li:{}".format(li))
for i in range(n - 1, -1, -1): # n-1开始到0
# i指向当前堆的最后一个元素
li[0], li[i] = li[i], li[0]
sift(li, 0, i - 1) # i-1是新的high
print("逐个出数li:{}".format(li))