数据结构复习总结之快速排序(四)

今天学一下快速排序
哦对了,吉大今天成立人工智能学院啦~~~,6的不行

原理概述

快速排序和插入排序,选择排序不太一样,后两个都是会把原来的序列分成两部分,有序和无序,然后操作其中一部分序列(插入排序是操作有序序列:取无序序列的第一个元素,在有序序列中选一个位置插入进去;选择排序是操作无序部分:选一个最小的追加到有序序列的后边)

快速排序主要是对于一个元素需要找到它在剩余序列中的合适位置,也就是序列中位于它左边的都比该值要小,位于该元素右边的都比该元素要大,这一过程需要两个游标来控制,核心思想(并非完整代码,只是提供了核心的操作)就是:

#****************************快速排序***********************************

L=[2,6,1,3,0,4,8,5]        
mid_value=2

if L[high]<mid_value:
    L[low]=L[high]
    low+=1
elif L[high]>mid_value:
    high-=1

if L[low]<mid_value:
    low+=1
elif L[low]>mid_value:
    L[high]=L[low]
    high-=1
#*********************************详细介绍分割线*************************************

首先我们需要明确的是快速排序虽然每次找到某一个元素的中心位置之后会把原来的序列分成左右两个部分再分别使用快速排序的思想

但是本质上来说,对元素的操作仍然是在原序列上进行的(代码中quick_sort的参数才会有first,last 代表操作的子序列在原序列中的哪段,这就保证了元素仍然是在原来的序列上进行的)

对于某一个元素(mid_value)在查找该元素在原来序列中的合适位置时都会需要两个游标low,high来进行双面夹击??现在大致说一下过程:

首先最初始的条件:low=first(=0),high=last(=n-1) 然后mid_value=L[first](因为每次要插入合适位置的元素mid_value都是子序列的第一个元素也就是first)

1.判断high指针上的元素,符合条件的移动high指针的位置:
先从high游标开始,比较这个位置上的元素和mid_value值的大小,如果L[high]>=mid_value 符合条件,就会让high指针不断左移(high-=1)
当high指针在移动的过程中出现L[high] < mid_value ,那么会退出循环,并且把这个high位置上比mid_value小的元素放在low位置上,high指针先原地不动;

2**接着就是判断low指针对应的元素,然后移动low的位置:**
跟上述思路差不多,首先判断L[low] < mid_value是否成立 成立则向前移动low的位置,一旦出现low所对应位置的元素比mid_value大则推出循环,并且把此时low位置上的元素放在high的位置即L[high]=L[low],然后low指针原地不动

然后又该操作high指针了,很明显就是一个不断循环的过程也就是不断循环进行1,2两个步骤所以最外层需要加一个循环判断,循环结束跳出循环的条件就是low和high 指向同一个位置,此时就是mid_value应该插入的位置,(即while low < high )

此时把mid_value的值放进去:L[low]=mid_value(L[high]一样的,因为low,high指向同一个位置)

扫描二维码关注公众号,回复: 1095468 查看本文章

3.递归调用,退出循环之后(也就是找到放此次mid_value的值之后)需要进行的是以mid_value为中心分成的左右两个子序列在进行同样的查找移动,其实也就是递归调用,只不过这里的参数很明显跟刚才不一样了,对于mid_value左边的序列first,last 的值分别为first,low-1右边的序列分别为low+1,lat 这样对生成的子序列也可以使用上述方法进行快速排序啦

代码实现
# -*- coding: utf-8 -*-
"""
Created on Sun May 27 14:28:28 2018

@author: Administrator
"""

#********************************快速排序(by_teacher)********************************
def quick_sort(L,first,last):#需要操作的序列以及序列的起始位置和重点位置


    if first>=last:
        return 

    mid_value=L[first] #每一次需要处理的元素都是子序列的第一个位置的元素
    low=first #需要设置两个游标,用来遍历序列(不断移动来找到mid_value的合适位置)
    high=last

    while low<high:

        while low<high and L[high]>=mid_value:
            high-=1
        L[low]=L[high]

        while low<high and L[low]<mid_value:
            low+=1
        L[high]=L[low]

    L[low]=mid_value

    quick_sort(L,first,low-1)
    quick_sort(L,low+1,last)

if __name__=="__main__":
    L=[7,4,1,8,2,9,6,0,3]
    print("快速排序之前:",L)
    quick_sort(L,0,8)
    print("快速排序之后:",L)

时间复杂度

快速排序最优的时间复杂度为n log n ,因为对于每一次找mid_value的位置时都是需要n的复杂度(因为low走左半边,high走右半边,最后碰面,刚好走了n长度)
然后最优的情况就是每一次mid_value都是在中间也就是把序列分成左右两个子序列(第一次查找分成两个,第二次查找每一个又都分成两个子序列,总共有4个,下一次查找分为8个 ,,,也就是经过x次 会把原来完整的序列分成n个子序列(也就是每一个子序列都是一个元素)这时才会停止:2^x=n===>x=log n)对于每一次查找都是n的复杂度(因为不管分成几个子序列,查找的长度都是子序列的长度,也就是总的来说还是n)所以最终的时间复杂度就是nlogn

稳定性

快速排序算法是不稳定的,它会打破原来的顺序~~

晚上要出去玩啦~~~

猜你喜欢

转载自blog.csdn.net/jiaowosiye/article/details/80464971