快速排序

快排

描述:

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

我的理解:

     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
原文地址:https://www.cnblogs.com/amou/p/9040357.html