數據結構複習總結之快速排序(四)

今天學一下快速排序
哦對了,吉大今天成立人工智能學院啦~~~,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指向同一個位置)

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

穩定性

快速排序算法是不穩定的,它會打破原來的順序~~

晚上要出去玩啦~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章