1. 程式人生 > >JavaScript實現排序演算法

JavaScript實現排序演算法

## JavaScript實現排序演算法 ### 一、大O表示法 **大O表示法:** * 在計算機中採用**粗略的度量**來描述計算機演算法的**效率**,這種方法被稱為**“大O”表示法** * 在**資料項個數**發生改變時,**演算法的效率**也會跟著改變。所以說演算法A比演算法B快兩倍,這樣的比較是**沒有意義**的。 * 因此我們通常使用**演算法的速度**隨著**資料量的變化**會如何變化的方式來表示演算法的效率,大O表示法就是方式之一。 **常見的大O表示形式** | 符號 | 名稱 | | ------------ | -------------- | | O(1) | 常數 | | O(log(n)) | 對數 | | O(n) | 線性 | | O(nlog(n)) | 線性和對數乘積 | | O(n²) | 平方 | | O(2^n^) | 指數 | **不同大O形式的時間複雜度:** ![image-20200304164951223](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/1.png) 可以看到效率從大到小分別是:O(1)> O(logn)> O(n)> O(nlog(n))> O(n²)> O(2^n^) **推導大O表示法的三條規則:** * **規則一**:用常量1取代執行時間中所有的加法常量。如7 + 8 = 15,用1表示運算結果15,大O表示法表示為O(1); * **規則二**:運算中只保留最高階項。如N^3 + 3n +1,大O表示法表示為:O(N^3^); * **規則三**:若最高階項的常數不為1,可將其省略。如4N^2^,大O表示法表示為:O(N^2^); ### 二、排序演算法 這裡主要介紹幾種簡單排序和高階排序: * **簡單排序:**氣泡排序、選擇排序、插入排序; * **高階排序:**希爾排序、快速排序; 此處建立一個列表類ArrayList並新增一些屬性和方法,用於存放這些排序方法: ``` //建立列表類 function ArrayList() { //屬性 this.array = [] //方法 //封裝將資料插入到陣列中方法 ArrayList.prototype.insert = function(item){ this.array.push(item) } //toString方法 ArrayList.prototype.toString = function(){ return this.array.join('-') } //交換兩個位置的資料 ArrayList.prototype.swap = function(m, n){ let temp = this.array[m] this.array[m] = this.array[n] this.array[n] = temp } ``` #### 1.氣泡排序 **氣泡排序的思路:** * 對未排序的各元素**從頭到尾**依次比較**相鄰的兩個元素**大小關係; * 如果**左邊的人員高**,則將兩人**交換位置**。比如1比2矮,不交換位置; * 向**右移動一位**,繼續比較2和3,最後比較 length - 1 和 length - 2這兩個資料; * 當到達**最右端**時,**最高的人**一定被放在了**最右邊**; * 按照這個思路,從最左端重新開始時,只需要走到**倒數第二個位置**即可; ![image-20200304191223265](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/2.png) **實現思路:** 兩層迴圈: * 外層迴圈控制冒泡趟數: * 第一次:j = length - 1,比較到倒數第一個位置 ; * 第二次:j = length - 2,比較到倒數第二個位置 ; * 內層迴圈控制每趟比較的次數: * 第一次比較: i = 0,比較 0 和 1 位置的兩個資料; * 最後一次比較:i = length - 2,比較length - 2和 length - 1兩個資料; 詳細過程如下圖所示: ![image-20200304210611689](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/3.png) 動態過程: ![](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/4.gif) **程式碼實現:** ``` //氣泡排序 //氣泡排序 ArrayList.prototype.bubblesor = function(){ //1.獲取陣列的長度 let length = this.array.length //外層迴圈控制冒泡趟數 for(let j = length - 1; j >= 0; j--){ //內層迴圈控制每趟比較的次數 for(let i = 0; i < j; i++){ if (this.array[i] > this.array[i+1]) { //交換兩個資料 let temp = this.array[i] this.array[i] = this.array[i+1] this.array[i+1] = temp } } } } ``` **測試程式碼:** ``` //測試類 let list = new ArrayList() //插入元素 list.insert(66) list.insert(88) list.insert(12) list.insert(87) list.insert(100) list.insert(5) list.insert(566) list.insert(23) //驗證氣泡排序 list.bubblesor() console.log(list); ``` **測試結果:** ![image-20200304210433388](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/5.png) **氣泡排序的效率:** * 上面所講的對於7個數據項,比較次數為:6 + 5 + 4 + 3 + 2 + 1; * 對於N個數據項,**比較次數**為:(N - 1) + (N - 2) + (N - 3) + ... + 1 = N * (N - 1) / 2;如果兩次比較交換一次,那麼**交換次數**為:N * (N - 1) / 4; * 使用大O表示法表示比較次數和交換次數分別為:O( N * (N - 1) / 2)和O( N * (N - 1) / 4),根據大O表示法的三條規則都化簡為:**O(N^2)**; #### 2.選擇排序 **選擇排序改進了氣泡排序:** * 將**交換次數**由**O(N^2)**減小到**O(N)**; * 但是**比較次數**依然是**O(N^2)**; **選擇排序的思路:** * 選定**第一個索引的位置**比如1,然後依次和後面的元素**依次進行比較**; * 如果後面的元素,**小於**索引1位置的元素,則**交換位置**到索引1處; * 經過一輪的比較之後,可以確定一開始指定的索引1位置的元素是**最小的**; * 隨後使用同樣的方法除索引1意外**逐個比較剩下的元素**即可; * 可以看出選擇排序,**第一輪**會選出**最小值**,**第二輪**會選出**第二小的值**,直到完成排序。 ![image-20200304213253241](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/6.png) **實現思路:** 兩層迴圈: * 外層迴圈控制指定的索引: * 第一次:j = 0,指定第一個元素 ; * 最後一次:j = length - 1,指定最後一個元素 ; * 內層迴圈負責將指定索引(i)的元素與剩下(i - 1)的元素進行比較; 動態過程: ![](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/7.gif) **程式碼實現:** ``` //選擇排序 ArrayList.prototype.selectionSort = function(){ //1.獲取陣列的長度 let length = this.array.length //2.外層迴圈:從0開始獲取元素 for(let j = 0; j < length - 1; j++){ let min = j //內層迴圈:從i+1位置開始,和後面的元素進行比較 for(let i = min + 1; i < length; i++){ if (this.array[min] > this.array[i]) { min = i } } this.swap(min, j) } } ``` **測試程式碼:** ``` //測試類 let list = new ArrayList() //插入元素 list.insert(66) list.insert(88) list.insert(12) list.insert(87) list.insert(100) list.insert(5) list.insert(566) list.insert(23) //驗證選擇排序 list.selectionSort() console.log(list); ``` **測試結果:** ![image-20200304222224801](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/8.png) **選擇排序的效率:** * 選擇排序的**比較次數**為:N * (N - 1) / 2,用大O表示法表示為:**O(N^2)**; * 選擇排序的**交換次數**為:(N - 1) / 2,用大O表示法表示為:**O(N)**; * 所以選擇排序的效率高於氣泡排序; #### 3.插入排序 插入排序是簡單排序中效率**最高**的一種排序。 **插入排序的思路:** * 插入排序思想的核心是**區域性有序**。如圖所示,X左邊的人稱為**區域性有序**; * 首先指定一資料X(從第一個資料開始),並將資料X的左邊變成區域性有序狀態; * 隨後將X右移一位,再次達到區域性有序之後,繼續右移一位,重複前面的操作直至X移至最後一個元素。 ![image-20200304231400959](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/9.png) 插入排序的詳細過程: ![image-20200304231643777](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/10.png) 動態過程: ![](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/11.gif) **程式碼實現:** ``` //插入排序 ArrayList.prototype.insertionSort = function(){ //1.獲取陣列的長度 let length = this.array.length //2.外層迴圈:從第二個資料開始,向左邊的已經區域性有序資料進行插入 for(let i = 1; i < length; i++){ //3.內層迴圈:獲取i位置的元素,使用while迴圈(重點)與左邊的區域性有序資料依次進行比較 let temp = this.array[i] let j = i while(this.array[j - 1] >
temp && j > 0){ this.array[j] = this.array[j - 1]//大的資料右移 j-- } //4.while迴圈結束後,index = j左邊的資料變為區域性有序且array[j]最大。此時將array[j]重置為排序前的資料array[i],方便下一次for迴圈 this.array[j] = temp } } ``` **測試程式碼:** ``` //測試類 let list = new ArrayList() //插入元素 list.insert(66) list.insert(88) list.insert(12) list.insert(87) list.insert(100) list.insert(5) list.insert(566) list.insert(23) // console.log(list); //驗證插入排序 list.insertionSort() console.log(list); ``` **測試結果:** ![image-20200304235529516](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/12.png) **插入排序的效率:** * **比較次數:**第一趟時,需要的最大次數為1;第二次最大為2;以此類推,最後一趟最大為N-1;所以,插入排序的總比較次數為N * (N - 1) / 2;但是,實際上每趟發現插入點之前,平均只有全體資料項的一半需要進行比較,所以比較次數為:**N * (N - 1) / 4**; * **交換次數:**指定第一個資料為X時交換0次,指定第二個資料為X最多需要交換1次,以此類推,指定第N個數據為X時最多需要交換N - 1次,所以一共需要交換N * (N - 1) / 2次,平局次數為**N * (N - 1) / 2**; * 雖然用大O表示法表示插入排序的效率也是**O(N^2)**,但是插入排序整體操作次數更少,因此,在簡單排序中,插入排序**效率最高**; #### 4.希爾排序 **希爾排序**是**插入排序**的一種高效的**改進版**,效率比插入排序要**高**。 **希爾排序的歷史背景:** * 希爾排序按其設計者希爾(Donald Shell)的名字命名,該演算法由**1959年公佈**; * 希爾演算法首次突破了計算機界一直認為的**演算法的時間複雜度都是O(N^2)**的大關,為了紀念該演算法里程碑式 的意義,用**Shell**來命名該演算法; **插入排序的問題:** * 假設一個**很小的資料項**在**很靠近右端的位置**上,這裡本應該是**較大的資料項的位置**; * 將這個**小資料項移動到左邊**的正確位置,所有的**中間資料項都必須向右移動一位**,這樣效率非常低; * 如果通過**某種方式**,不需要**一個個移動所有中間的資料項**,就能把較小的資料項移到左邊,那麼這個演算法的執行速度就會有很大的改進。 **希爾排序的實現思路:** * 希爾排序主要通過對資料進行**分組**實現快速排序; * 根據設定的增量(gap)將資料分為gap個組(**組數等於gap**),再在每個分組中進行區域性排序; >
假如有陣列有10個數據,第1個數據為黑色,增量為5。那麼第二個為黑色的資料index=5,第3個數據為黑色的資料index = 10(不存在)。所以黑色的資料每組只有2個,10 / 2 = 5一共可分5組,即**組數等於增量gap**。 * 排序之後,減小增量,繼續分組,再次進行區域性排序,直到增量gap=1為止。隨後只需進行微調就可完成陣列的排序; 具體過程如下: * 排序之前的,儲存10個數據的原始陣列為: ![image-20200305102330304](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/13.png) * 設初始增量gap = length / 2 = 5,即陣列被分為了5組,如圖所示分別為:[8, 3]、[9, 5]、[1, 4]、[7, 6]、[2, 0]: ![image-20200305104914438](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/14.png) * 隨後分別在每組中對資料進行區域性排序,5組的順序如圖所示,變為:[3, 8]、[5, 9]、[1, 4]、[6, 7]、[0, 2]: ![image-20200305103136251](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/15.png) * 然後縮小增量gap = 5 / 2 = 2,即陣列被分為了2組,如圖所示分別為:[3,1,0,9,7]、[5,6,8,4,2]: ![image-20200305104933858](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/16.png) * 隨後分別在每組中對資料進行區域性排序,兩組的順序如圖所示,變為:[0,1,3,7,9]、[2,4,5,6,8]: ![image-20200305103815262](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/17.png) * 然後然後縮小增量gap = 2 / 1 = 1,即陣列被分為了1組,如圖所示為:[0,2,1,4,3,5,7,6,9,8]: ![image-20200305104847458](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/18.png) * 最後只需要對該組資料進行插入排序即可完成整個陣列的排序: ![image-20200305104707789](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/19.png) 動態過程: ![](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/20.gif) 圖中d表示增量gap。 **增量的選擇:** * **原稿**中希爾建議的初始間距為**N / 2**,比如對於N = 100的陣列,增量序列為:50,25,12,6,3,1,可以發現不能整除時向下取整。 * **Hibbard增量序列:**增量序列演算法為:2^k - 1,即1,3,5,7... ...等;這種情況的最壞複雜度為**O(N^3/2)**,平均複雜度為**O(N^5/4)**但未被證明; * **Sedgewcik增量序列:** ![image-20200305110724309](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/21.png) 以下程式碼實現中採用希爾排序原稿中建議的增量即**N / 2** 。 **程式碼實現:** ``` //希爾排序 ArrayList.prototype.shellSort = function(){ //1.獲取陣列的長度 let length = this.array.length //2.初始化增量 let gap = Math.floor(length / 2) //3.第一層迴圈:while迴圈(使gap不斷減小) while(gap >
= 1 ){ //4.第二層迴圈:以gap為增量,進行分組,對分組進行插入排序 //重點為:將index = gap作為選中的第一個資料 for(let i = gap; i < length; i++){ let temp = this.array[i] let j = i //5.第三層迴圈:尋找正確的插入位置 while(this.array[j - gap] > temp && j > gap - 1){ this.array[j] = this.array[j - gap] j -= gap } //6.將j位置的元素設定為temp this.array[j] = temp } gap = Math.floor(gap / 2) } } ``` 這裡解釋一下上述程式碼中的三層迴圈: * **第一層迴圈:**while迴圈,控制gap遞減到1; * **第二層迴圈:**分別取出根據g增量gap分成的gap組資料:將index = gap的資料作為選中的第一個資料,如下圖所示,gap=5,則index = gap的資料為3,index = gap - 1的資料為8,兩個資料為一組。隨後gap不斷加1右移,直到gap < length,此時實現了將陣列分為5組。 ![image-20200305104914438](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/21.5.png) * **第三層迴圈:**對每一組資料進行插入排序; **測試程式碼:** ``` //測試類 let list = new ArrayList() //插入元素 list.insert(66) list.insert(88) list.insert(12) list.insert(87) list.insert(100) list.insert(5) list.insert(566) list.insert(23) // console.log(list); //驗證希爾排序 list.shellSort() console.log(list); ``` **測試結果:** ![image-20200305114934209](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/22.png) **希爾排序的效率:** * 希爾排序的效率和增量有直接關係,即使使用原稿中的增量效率都高於簡單排序。 #### 5.快速排序 快速排序的介紹: * **快速排序**可以說是**目前所有排序演算法**中,**最快**的一種排序演算法。當然,沒有任何一種演算法是在任意情況下都是最優的。但是,大多數情況下快速排序是比較好的選擇。 * **快速排序**其實是**氣泡排序**的升級版; 快速排序的核心思想是**分而治之**,先選出一個數據(比如65),將比其小的資料都放在它的左邊,將比它大的資料都放在它的右邊。這個資料稱為**樞紐** 和氣泡排序的不同: * 我們選擇的65可以一次性將它放在最正確的位置,之後就不需要做任何移動; * 而氣泡排序即使已經找到最大值,也需要繼續移動最大值,直到將它移動到最右邊; ![image-20200305154504624](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/23.png) **快速排序的樞紐:** * **第一種方案:**直接選擇第一個元素作為樞紐。但是,當第一個元素就是最小值的情況下,效率不高; * **第二種方案:**使用隨機數。隨機數本身十分消耗效能,不推薦; * **優秀的解決方法:**取index為頭、中、位的三個資料排序後的中位數;如下圖所示,按下標值取出的三個資料為:92,31,0,經排序後變為:0,31,92,取其中的中位數31作為**樞紐**(當(length-1)/2不整除時可向下或向上取整): ![image-20200305182934710](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/24.png) **實現樞紐選擇:** ``` //交換兩個位置的資料 let swap = function(arr, m, n){ let temp = arr[m] arr[m] = arr[n] arr[n] = temp } //快速排序 //1.選擇樞紐 let median = function(arr){ //1.取出中間的位置 let center = Math.floor(arr.length / 2) let right = arr.length - 1 let left = 0 //2.判斷大小並進行交換 if (arr[left] > arr[center]) { swap(arr, left, center) } if (arr[center] > arr[right]){ swap(arr, center, right) } if (arr[left] > arr[right]) { swap(arr, left, right) } //3.返回樞紐 return center } ``` 陣列經過獲取樞紐函式操作之後,選出的3個下標值對應的資料位置變為: ![image-20200320091750654](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/25.png) **動態過程:** ![](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/26.gif) **快速排序程式碼實現:** ``` //2.快速排序 let QuickSort = function(arr){ if (arr.length == 0) { return [] } let center = median(arr) let c = arr.splice(center, 1) let l = [] let r = [] for (let i = 0; i < arr.length; i++) { if (arr[i] < c) { l.push(arr[i]) }else{ r.push(arr[i]) } } return QuickSort(l).concat(c, QuickSort(r)) } ``` 演算法的巧妙之處在於通過: ``` QuickSort(l).concat(c, QuickSort(r)) ``` 遞迴呼叫`QuickSort`函式實現了樞紐`Center`左邊資料`l`和右邊資料`r`的排序; **測試程式碼:** ``` let arr = [0, 13, 81, 43, 31, 27, 56, 92] console.log(QuickSort(arr)); ``` **測試結果** ![image-20200320092254048](https://gitee.com/ahuntsun/BlogImgs/raw/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/28.png) **快速排序的效率:** * 快速排序最壞情況下的效率:每次選擇的樞紐都是最左邊或最右邊的資料,此時效率等同於氣泡排序,時間複雜度為**O(n^2^)**。可根據不同的樞紐選擇避免這一情況; * 快速排序的平均效率:為**O(N*logN)**,雖然其他演算法效率也可達到O(N*logN),但是其中快速排序是**最好的**。 > 參考資料:[JavaScript資料結構與演算法](https://www.bilibili.com/video/av86801505?from=search&seid=496776141191