zoukankan      html  css  js  c++  java
  • 算法: 快排, 堆排, 合并排序

    1 快排:

    data = [2, 5, 1, 6, 3, 9, 7]
    def quick_sort(data, left, right):
        if left < right:
            # 1 确定中间数的位置, 求出中间数的索引
            mid = partition(data, left, right)
            print(mid)
            # 2 对剩余的两部分排序, 采用递归
            quick_sort(data, left, mid - 1)
            quick_sort(data, mid + 1, right)
        print(data)
    def partition(data, left, right):
        tmp = data[left]
        while left < right:
            # 加left < right的原因: 由于跳不出循环, 所以加上条件, 要么是left +1 , 或者是right - 1. 
            while tmp < data[right] and left < right:
                right = right - 1
            data[left] = data[right]
            while tmp > data[left] and left < right:
                left = left + 1
            data[right] = data[left]
        data[left] = tmp
        return left
    quick_sort(data, 0, len(data) - 1)
    View Code

    2 堆排:

      a :堆的相关知识:

    树是一种数据结构, 比如目录结构
    二叉树--是一种特殊且常用的树:  度不超过2的树(节点最多有两个叉)
      满二叉树: 每一个节点都达到最大值,这个二叉树成为满二叉树
      完全二叉树:叶节点只能出现在最下层和次下层, 并且最下层的节点都集中在该层的最左边的若干位置的二叉树.
    二叉树的两种存储方式:  链式存储和顺序存储(列表)
        二叉树可以用列表来存储,通过规律找到父亲或从孩子找到父亲.
    
    堆: 大根堆: 一颗完全二叉树, 满足任一节点都比其孩子节点大
        小跟堆: 一颗完全二叉树, 满足任一节点都比其孩子节点小
    View Code

        b : 堆排序的过程:

    # 1 建立堆(从最后一个根节点开始调整)
    # 2 得到堆顶元素为最大元素
    # 3  去掉堆顶, 将堆最后一个元素放到堆顶, 此时可通过一次调整重新使堆有序
    # 4 堆顶元素为第二大元素
    # 5 重复步骤三, 直到堆变空
    View Code

      c : 堆的向下调整:

    def sift(li, low, high):
        tmp = li[low]
        print('low', low)
        i = low
        j = 2 * i + 1
        # 此时要进行循环, 因为要进行多次:
        while j <= high:  # 第二种情况退出:   i 已经是最后一层了
            if j < high and li[j] < li[j + 1]:  # 当右节点存在且右节点比左节点值大
                j = j + 1
            if li[j] > tmp:  # 当子节点的值比父节点的值大的时候, 交换, 获取新的i和j
                li[i] = li[j]
                i = j
                j = 2 * i + 1
            else:
                break  # 第一种情况退出:  tmp的值比j位置的值大
        li[i] = tmp
        return li
    View Code

      d : 堆排代码:

    def heap_sort(data):
        # 构建堆
        n = len(data)
        print("n", n)
        for low in range(n // 2 - 1, -1, -1):
            # 构建堆的过程,从最后一个根节点开始.
            sift(data, low, n - 1)
            print('data', data)
        # 挨个出数
        for high in range(n - 1, -1, -1):
            data[0], data[high] = data[high], data[0]
            sift(data, 0, high - 1)
        return data
    print(heap_sort([2, 6, 8, 7, 4, 3, 1, 0]))
    # 先构建堆, 再进行调整
    View Code

    3 合并排序  

      a : 原理: 

        分解 将列表越分越小,直至分成一个元素

        终止条件:一个元素是有序的

        分解: 将两个有序列表合并,列表越来越大

      b : 一次归并的代码:

        对于一个列表, low表示开始, high表示结束的索引, mid表示中间值,用左半部分的值和右半部分的值进行比较.

    # 一次合并
    def merge(li, low, mid, high):
        i = low
        j = mid + 1
        li_temp = []
        # 左右两边都有值的情况
        while i <= mid and j <= high:
            if li[i] < li[j]:
                li_temp.append(li[i])
                i = i + 1
            else:
                li_temp.append(li[j])
                j = j + 1
        # 只剩下左边的值, while有if的作用
        while i <= mid:
            li_temp.append(li[i])
            i = i + 1
        # 只剩下右边的值
        while j <= high:
            li_temp.append(li[j])
            j = j + 1
        for k in range(low, high + 1):
            li[k] = li_temp[k - low]
        return li
    View Code

      c :合并的代码:

    def merge_sort(li, low, high):
        if low < high:
            mid = (low + high) // 2
            print(li[low:mid+1],li[mid+1:high+1])
            # 递归左半部分
            merge_sort(li, low, mid)
            # 递归右半部分
            merge_sort(li, mid + 1, high)
            # 归并
            merge(li,low,mid,high)
            print(li[low:mid+1],li[mid+1:high+1])
    li = [10, 4, 6, 3, 8, 5, 2, 7]
    print(merge_sort(li,0,(len(li)-1)))
    print(li)
    View Code

      d : 合并算法的时间复杂度:

        一次归并的时间复杂度是o(n)

        mid一次的时间复杂度是0(1),分解了logn次, 时间复杂度是logn

        合并的过程是nlogn

        即时间复杂度是:nlogn

     4 三种算法的总结:

      a : 时间复杂度都是o(nlogn)

      b : 效率: 快排 >归并>堆排

      c : 三种算法的优缺点:

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

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

        堆排序: 在快的排序算法中,相对较慢, 但应用很广.

        

  • 相关阅读:
    Remove Duplicates from Sorted List II [LeetCode]
    Valid Palindrome [LeetCode]
    Merge Sorted Array [LeetCode]
    Binary Tree Postorder Traversal
    Subsets [LeetCode]
    Search for a Range [LeetCode]
    Reorder List [LeetCode]
    GCC 默认用哪个标准
    18 组装类举例
    17 实例方法、静态方法、类方法
  • 原文地址:https://www.cnblogs.com/gyh412724/p/10140209.html
Copyright © 2011-2022 走看看