快速排序的性能和名字一样优秀
前言
上次分享的冒泡排序雖然比較簡單、容易理解,但每一次冒泡的過程都需要依次比較相鄰的元素,然后交換,可見性能還是有很大的優(yōu)化空間,只要能減少比較次數(shù),性能自然就上去啦;快速排序便是一個很不錯的選擇~~~
正文
1.1 快速排序算法思想
快速排序(Quicksort)是對上一次分享的冒泡排序算法的一種改進,主要是減少比較次數(shù),以此來提高排序性能;也屬于交換排序的一種。
算法思想
在待排序列表中任取一個元素作為基準值;
將剩下的元素和基準值依次比較,小于的放左邊,大于的放右邊,最后通過一趟排序?qū)⒋判蛄斜矸譃樽笥覂刹糠?#xff0c;這個過程稱為一次“劃分”;
然后用同樣的方法分別在左右兩部分中取基準值進行排序,依次遞歸,直到劃分的每部分內(nèi)只有一個元素或空為止,則排序結(jié)束。
1.2 快速排序算法實現(xiàn)與解析
算法實現(xiàn)
劃分代碼實現(xiàn),每一次取對應(yīng)部分的首位元素作為基準值,然后通過依次比較,將對應(yīng)數(shù)據(jù)又在細分為左右兩部分,如下實現(xiàn):
image-20210506133026759使用遞歸進行劃分排序,直到只有一個元素或為空為止:
image-20210506133313691運行效果
image-20210506133449121步驟解析(升序):
image-20210506135153320上圖步驟說明:
上圖演示是針對數(shù)組array進行升序排序,第一次以全部數(shù)據(jù)為一組,low為0,high為5,選擇low位元素2為基準值(即第一個元素),開始進行比較:
第1.1步:由于剛開始選擇low位的元素為基準值(可以認為這個位置空了),所以接下來開始從high位開始遍歷比較,high位元素3大于2,不用交換位置,high減1,繼續(xù)比較;
第1.2步:此時low為0,high為4,high位元素9大于2,不用交換位置,high減1,繼續(xù)比較;
第1.3步:此時low為0,high為3,high位元素1小于2,需要將high位元素1放到基準值的左邊,則將元素1放到low指向的位置;
第1.4步:此時low為0,high為3,由于high位已經(jīng)交換過了(可以認為這個位置空了),所以這次開始到low位進行遍歷比較,low位元素是剛交換過來的,所以不用交換位置;low加1繼續(xù)比較,此時low為1,對應(yīng)位置的元素5大于基準值2,所以需要將元素5放到基準值的右邊,則將元素5放到high指向位置;
第1.5步:此時low為1,high為3,由于low位已經(jīng)交換過了(可以認為這個位置空了),所以這次又回到high位進行遍歷比較,high位元素是剛交換過來的,所以不用交換位置;high減1繼續(xù)比較,此時high為2,對應(yīng)位置元素6大于基準值2,所以不用交換位置,high減1,繼續(xù)比較;
第1.6步:此時low為1,high為1,此時代表第一次劃分排序完成,則將基準值放到這個位置;最終將原始數(shù)據(jù)分為左右兩部分,左部分只有一個元素1,不用再劃分了,右部分有6,5,9,3四個元素,繼續(xù)對于右部分進行劃分;
第2.1步:由于右部分是從索引位2開始,所以此時low為2,high為5,基準值為low為的元素6;
第2.2步:由于剛開始選擇low位的元素為基準值(可以認為這個位置空了),接下來從high為開始遍歷比較,high為元素3小于基準元素6,需要將其放到基準元素的左邊,則將元素3放到low指向的位置。
第2.3步:此時low為2,high為5,由于high位已經(jīng)交換過了(可以認為這個位置空了),所以這次開始到low位進行遍歷比較,low位元素是剛交換過來的,所以不用交換位置;low加1繼續(xù)比較,此時low為3,對應(yīng)位置的元素5小于6,不需要交換元素,則low加1,繼續(xù)比較;
第2.4步:此時low為4,high為5,low位對應(yīng)的元素9大于基準值6,所以需要將其放到基準元素的右邊,則將元素9放到high指向的位置。
第2.3步:此時low為4,high為5,由于low位已經(jīng)交換過了(可以認為這個位置空了),所以這次開始到high位進行遍歷比較,high位元素是剛交換過來的,所以不用交換位置;high減1繼續(xù)比較,此時high為4,此時low和high都為4,找到此次劃分基準值的位置,則將基準元素6的放到4位置;到這又將原來的右部分6,5,9,3四個元素劃分為左右兩部分,右邊只有一個元素9,不用繼續(xù)劃分;左邊有元素3和5,繼續(xù)劃分排序;(這里就不重復(fù)演示)
最終通過遞歸劃分排序的方式,直到每個劃分部分內(nèi)只有一個元素或空為止,即可獲得最后的排序結(jié)果。
1.3 快速排序算法分析
時間復(fù)雜度
從上面解析步驟得知,每一次排序都是只需要處理剩下未排序的元素,每一次排序時間復(fù)雜度不會超過O(n),但由于是通過遞歸進行劃分排序,所以快速排序的整體時間復(fù)雜度和遞歸層數(shù)有關(guān),即總的時間復(fù)雜度為O(n*遞歸層數(shù));
通過上面演示得知,其實最終將待排序數(shù)據(jù)劃分為一個二叉樹結(jié)構(gòu),在這二叉樹的高度就代表遞歸的層數(shù)(后續(xù)會專門分享這塊內(nèi)容),如下圖:
image-20210506143932543關(guān)于n個元素的二叉樹的最小高度為(log2n)+1,最大高度為n,如果待排序數(shù)據(jù)已經(jīng)有序或逆序,如果每次都選擇每部分的首個元素為基準值,這樣就會導(dǎo)二叉樹高度增加,即遞歸深度就會增加;所以快速排序的時間復(fù)雜度最好為O(nlog2n),最壞為O(n2);
這樣以為快速排序就不行了嗎?當然不是,可以隨機選一個元素做為基準值,這樣不管待排序數(shù)據(jù)為有序還是逆序,都不會導(dǎo)致遞歸深度太深。所以最后快速排序的平均時間復(fù)雜度為O(nlog2n)
空間復(fù)雜度
空間復(fù)雜度在每次遞歸當中,用到的變量都是固定的(pivot,low,high),則最終影響空間復(fù)雜度的因素還是遞歸層數(shù),則快速排序空間復(fù)雜度為O(遞歸層數(shù)), 最好為O(log2n),最壞為O(n)。
穩(wěn)定性
由于是用待排序數(shù)據(jù)和基準值進行比較,所以最終元素交換位置不是固定的,則不能保證兩個相等元素原有順序不變,則快速排序是不穩(wěn)定的。如下圖:
image-20210506150331140如果取low位置的元素3作為基準值,最終會和元素2進行交換,最后就不能保證原來相等元素的前后順序了。
綜上所述,快速排序的時間復(fù)雜度為O(nlog2n),空間復(fù)雜度為O(log2n),是不穩(wěn)定算法;
總結(jié)
快速排序有效的解決了冒泡排序的缺陷,減少了比較次數(shù),提升了排序性能。但當待排序列表為有序或逆序時,如果單純的取第一個元素或最后一個元素作為基準值,排序性能并沒有提升。所以實現(xiàn)排序算法的關(guān)鍵是需要選個好的基準值,比如可以隨機選擇,也可以定義一個規(guī)則選擇,看小伙伴的實現(xiàn)方式咯。
感謝小伙伴的:點贊、收藏和評論,下期繼續(xù)~~~
一個被程序搞丑的帥小伙,關(guān)注"Code綜藝圈",跟我一起學(xué)~~~
總結(jié)
以上是生活随笔為你收集整理的快速排序的性能和名字一样优秀的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 答群友:把窗体应用改成类库输出然后
- 下一篇: 你可能会用到的 Mock 小技巧