python算法之lowB三人组和牛逼3人组

排序算法

排序Low B三人组

冒泡排序

列表每两个相邻的数,如果前边的比后边的大,那么交换这两个数

def bubble_sort(li):
    for i in range(len(li) - 1):
        exchange = False
        for j in range(len(li) - i - 1):
            if li[j] > li[j+1]:
                li[j], li[j+1] = li[j+1], li[j]
                exchange = True
        if not exchange:
            break

选择排序

一趟遍历记录下最小的数,放在第一个位置:

接遍历剩余列表,继续放置:

# 如何查找最小值
def min_pos():
    min_pos = 0
    for i in range(1,len(li)):
        if li[i] < li[min_pos]:
            min_pos = i
     return min_pos
# 选择排序
def select_sort(li):
    for i in range(len(li) - 1):
        min_pos = i
        # 查找最小值
        for j in range(i+1,len(li)):
            if li[j] < li[mis_pos]:
                min_pos = j
        li[i], li[min_pos] = li[min_pos], li[i]
        

插入排序

列表被分为有序区和无序区两个部分。最初有序区只有一个元素。

每次从无序区选择一个元素,插入有序区的位置,直到无序区变空。

def insert_sort(li):
    for i in range(1,len(li)):
        tmp = li[i]
        j = i - 1
        while j >= 0 and li[j] > tmp:
            li[j+1] = li[j]
            j -= 1
        li[j+1] = tmp
        

牛逼三人组

快速排序(快)

什么是快速排序?

  • 取一个元素 p(第一个元素),是元素 p 归位
  • 列表被 p 分成两部分,左边都比 p 小,右边都比 p 大
  • 递归完成排序
def qiuck_sort(li, left, right):
    if left < right:
        mid = partition(li, left, right)
        qiuck_sort(li, left, mid-1)
        qiuck_sort(li, mid+1, left)

def patition(li,left,right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:
            left -= 1
        li[right] = li[left]
    li[left] = tmp
    reutrn left

第二种

def quick_sort2(li):
    return _quick_sort2(li)

def _quick_sort2(li):
    if len(li) < 2:
        return li
    tmp = li[0]
    left = [v for v in li[1:] if v <= tmp]
    right = [v for v in li[1:] if > tmp]
    left = _quick_sort2(left)
    right = _quick_sort2(right)
    return left + [tmp] + right

效率问题:

快排最坏是 O(N^2)

堆排序

完全二叉树

时间复杂度:O(nlogn)

# 构造堆(大根堆)
def sift(li, low, high):
    #  li表示树,low表示树根,high表示树最后一个节点
    tmp = li[low]
    i = low
    j = 2 * i + 1 # 初始 j  指向空位得左孩子
    # i 指向空位,j 指向两个孩子
	while  j <= high:
        if j + 1 <= high and li[j] < li[j+1]:
            # 如果右孩子存在并且比左孩子大,指向右孩子
            j += 1
        if li[j] > tmp:
            li[i] = li[j]
            i = j
            j = 2 * i + 1
        else:
            # 循环退出得第一种清空:j 位置得值比 tmp 小,说明两个孩子都比 tmp 小
            break
	li[i] = tmp
    
# 堆排序    
def heap_sort(li):
    n = len(li)
    # 1.构造堆
    for low in range(n // 2 - 1, -1, -1):
        sift(li, low, n-1)
    # 2.挨个出数
    for high in range(n - 1, -1, -1):
        li[0], lin[high] = li[high], li[0]  # 退休棋子
        sift(li, 0, high - 1)
        

python 内置模块 ——— heapq

利用模块实现堆排序

import heapq

li = [9,5,3,4,7,8,1,4]
heapq.heapify(li)
# 构建出来得是小根堆
print(li)

# heapq.heapqpush(heap, item)
heapq.heappush(li, 0)
# 往堆加元素,自动调整堆得顺序

# 获取 heapq 的最小值
item = heapq.heappop(li)
print(item)

# 最大5个数
heapq.nlargest(5, li)
# 最小5个数
heapq.nsmallest(5, li)

# 利用 heapq 模块实现堆排序
def heapsort(li):
    h = []
    for value in li:
        heappush(h, value)
    return [heappop(h) for i in range(len(h))]

拓展问题—— topK问题

现在有 n 个数,设计算法找出前 k 大的数(k

解决方法:

  1. 排序后切片
  2. low b 三人组思想 (冒泡 kn, 选择 kn , 插入nk)
  3. ?堆排,建小根堆(nlogk)

归并排序

假设现在的列表分成两段有序,如何将其合成一个有序序列

两两比较,排序

时间复杂度:O(nlogn)

空间复杂度:O(n)

def merge(li, low, mid, high):
    # 列表两段有序:[low, mid]  [mid+1, high]
    i = low
    j = mid + 1
    lis_tmp = []
    while i <= mid and j <= high:
        if li[i] < li[j]:
            lis_tmp.append(li[i])
            i += 1
        else:
            lis_tmp.append(li[j])
            j += 1
    while i <= mid:
        lis_tmp.append(li[i])
        i += 1
    while j <= high:
        lis_tmp.append(li[j])
        j += 1
    # lis_tmp[0:high - low+1]  li[low:high+1]
    for i in range(low, high + 1):
        li[i] = li_tmp[i-low]
    # li[low:high+1] = li_tmp
 
def merge_sort(li, low,high):
    # 排序 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)

两个有序的列表排序

# 两个有序的排列
def merge2list(li1, li2):
    li = []
    i = 0
    j = 0
    while i < len(li1) and j < len(li2):
        if li1[i] <= li2[j]:
            li.append(li1[i])
            i += 1
        else:
            li.append(li2[j])
            j += 1
    while i < len(li1):
        li.append(li1[i])
        i += 1
    while j < len(li2):
        li.append(li2[j])
        j += 1
    return li
            
            

三种都是O(nlogn)

一般情况下,就运行时间而言:

快速排序 < 归并排序 < 堆排序

三种排序算法的缺点:

快速排序:极端情况下排序效率低

归并排序:需要额外的内存开销

堆排序:在快的排序算法中相对较慢

你可能感兴趣的:(python,数据结构与算法)