zoukankan      html  css  js  c++  java
  • 快速排序

    快排

    描述:

      基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

    我的理解:

         1. 在列表内, 设置一个基准值, 找到该基准值的正确位置, 该位置的左侧部分,都比该位置的元素小, 右侧部分都比该位置的元素大

      2. 第1步结束后, 列表被分为两部分, 左侧与右侧
      3. 将这两部分都执行快速排序, 此时左部分被分为两半, 右部分被分为两半
      4. 循环执行1-3步
      5. 起始传递进来的列表, 按照二叉树的规则一直分, 直到被分之后的列表只有一个元素, 即该列表的起始下标等于终止下标
      6. 第5步结束后, 起始列表已经被排好序, 将该列表返回

    时间复杂度

      最优时间复杂度:O(nlogn)

       情况描述:

          每次设定的基准值, 经排序后, 该基准值恰巧为列表的中间值

       时间复杂度: 得分两种情况: 1: 分叉 2: 排序

          分叉: 列表以完全二叉树的情况, 进行分叉, 每次一分为二, 被分了n次

          即: 步骤为 log2^n

          排序: 每次排序都要对列表内所有的元素进行判断

          即: 步骤为 n

        由此得出时间复杂度为: O(T) = O(n * log2^n) = O(nlogn)

      最坏时间复杂度:O(n2)

        1. 情况描述:

        每次设定的基准值, 经排序后, 在列表的最左侧, 或 最右侧

        2. 时间复杂度得分两种情况: 分叉和排序

          分叉: 因为基准值一直在左侧, 或者右侧, 所以列表被分了n次

          即: 步骤为 n

          排序: 每次排序都要对列表内所有的元素进行判断

          步骤为 n

        由此得出时间复杂度为: O(T) = O(n * n) = O(n^2)

    稳定性:不稳定

       快速排序是从头和尾开始对元素进行比较,有可能把关键值相同的两个元素调换了位置,所有说是不稳定的,

      例如:

           对  2 4 1 3 1  进行排序,第一趟就把后面的1换到前面去,形成了不稳定排序

    代码:

    简洁版:

    def quick_sort(Li, first, last):
        if first >= last:
            return
        mid_value = Li[first]
        low = first
        high = last
        while low < high:
            while low < high and Li[high] >= mid_value:
                high -= 1
            Li[low] = Li[high]
            while low < high and Li[low] < mid_value:
                low += 1
            Li[high] = Li[low]
        Li[low] = mid_value
        quick_sort(Li, first, low)
        quick_sort(Li, low+1, last)
    View Code

    注释版:

    def quick_sort(Li, first, last):
        if first >= last:
            # first和last分别为传递进来列表的起始下标与终止下标
            # 如果, 起始下标小于终止下标, 则进行快排
            # 反之, 将引用返回
            return
        # 下面为快排代码
        mid_value = Li[first]
        # 先设置一个基准值, 一般都以列表的起始元素为基准值, 找到这个基准值的正确位置
        low = first
        high = last
        # 设置两个游标, low从列表左侧开始, high从列表右侧开始
        while low < high:
            # 如果low跟high不相遇, 则一直循环, 直到相遇, 即: 找到了基准值的正确位置
            while low < high and Li[high] >= mid_value:
                # 如果high指向的值, 比基准值大, 则向左移
                high -= 1
            Li[low] = Li[high]
            # 结束上面循环后, 代表high游标指向的值, 比基准值小, 将这个high元素与左侧的值进行交换
            while low < high and Li[low] < mid_value:
                # 如果high指向的值, 比基准值小, 则向右移
                low += 1
            Li[high] = Li[low]
            # 结束上面循环后, 代表low指向的值, 比基准值大, 将这个low元素与右侧的值进行交换
        Li[low] = mid_value
        # 上面大循环结束后代表找到了该列表基准值的正确位置, 也代表low游标与high游标相撞, 即: low=high
        # 将基准值 插入到正确的位置, low=high 所以: Li[low] = mid_value 或 Li[high] = mid_value  都可以
        # 将该列表的基准值, 插入到正确位置后, 此时, 列表分为两部分, 左侧部分都比它小, 右侧部分都比它大
        quick_sort(Li, first, low)
        # 将该列表的左侧部分, 进行快速排序
        quick_sort(Li, low+1, last)
        # 将该列表的右侧部分, 进行快速排序
        # 循此往复, 直到该列表所有元素都找到正确位置
    
        # ==================================
    
        # 快速排序,
        # 1. 在列表内, 设置一个基准值, 找到该基准值的正确位置, 该位置的左侧部分,都比该位置的元素小, 右侧部分都比该位置的元素大
        # 2. 第1步结束后, 列表被分为两部分, 左侧与右侧
        # 3. 将这两部分都执行快速排序, 此时左部分被分为两半, 右部分被分为两半
        # 4. 起始传递进来的列表, 按照二叉树的规则一直分, 直到被分之后的列表只有一个元素, 即该列表的起始下标等于终止下标
        # 5. 第4步结束后, 起始列表已经被排好序, 将该列表返回
    
    
    
    if __name__ == "__main__":
        l = list(i for i in range(0, 10000))
        print("洗牌之前的列表:" + str(l))
        random.shuffle(l)
        print("洗牌之后的列表:" + str(l))
        quick_sort(l, 0, len(l)-1)
        print(l)
    View Code
  • 相关阅读:
    类模型NLP 学习笔记 05 (Brown Clustering && Global Linear Models)
    nullnull精美的文言文表白,一起体会吧!
    [转载]ESFramework介绍之(31)―― 消息分类及对应的处理器
    【转载】ESFramework介绍之(23)―― AgileTcp
    [转载]ESFramework 4.0 快速上手(15) -- 客户端登录验证
    【转载】ESFramework介绍之(31)―― 消息分类及对应的处理器
    【转载】ESFramework 平台下可复用的Tcp通信层实现
    【转载】ESFramework介绍之(27)-- 支持OverdueMessage (离线消息)
    高性能的大型系统经验 -- 将数据分类、并缓存
    【转载】可复用的FS
  • 原文地址:https://www.cnblogs.com/amou/p/9040357.html
Copyright © 2011-2022 走看看