遞迴演算法學習系列之三(快速排序)

來源:互聯網
上載者:User

       上兩片第歸演算法學習:

1) 遞迴演算法學習系列一(分而治之策略)
2) 遞迴演算法學習系列二(歸併排序) 

     上一篇學習中介紹了了遞迴演算法在排序中的一個應用:歸併排序,在排序演算法中還有一種演算法用到了遞迴,那就是快速排序,快速排序也是一種利用了分而治之策略的演算法,它由C.A.R發明,它依據中心元素的值,利用一系列遞迴調用將資料表劃分成越來越小的子表。在每一步調用中,經過多次的交換,最終為中心元素找到最終的位置。與歸併演算法不同,快速排序是就地排序,而歸併排序需要把元素在臨時向量中拷貝,下面通過對以下向量進行排序來理解和加深快速排序演算法的步驟:

 v={800,150,300,650,550,500,400,350,450,400,900};

利用快速排序演算法對此資料表進行排序的第0級劃分過程如下: 向量v的索引範圍為:[first,last) = [0,10),則中心點的索引為mid = (0+10)/2=5,中心點的值為v[5] = 500

快速排序演算法的第一次劃分的目的就是將向量v依據v[5]的值劃分成兩個子表subList1和subList2,其中subList1中的值都小於v[5],而subList2中的值都大於v[5],我們將subList1稱為左子表,subList2稱為右子表,並且確定v[5]的最終位置:下面就是實現這一目的需要我們作出的工作步驟:

1)首先將中心元素與起始位置的元素進行交換。

2)分別掃描左子表和右子表,左子表掃描起始位置為 first+1, 右子表從last-1開始。左子表從左向右掃描掃描,右子表從右向左掃描。直到左子表掃描位置大於或者等於右子表掃描位置時候結束。

在第一個步驟中,得到如下的資料表

500  150  300 650 550 800 400 350 450 400  ,而此時的左子表掃描位置處於索引1處,右子表掃描位置處於索引9處,先從左子表掃描,直到找到資料值大於中間值500的位置停止掃描,然後掃描右子表,直到找到資料值小於中間值500並且右子表的掃描位置(scanDown)要小於左子表開始位置,防止資料溢出。找到之後,交換左子表與右子表中中掃描位置的元素,圖示如下: ,在交換v[3](650>500)與v[8](450<500)後,繼續掃描左子表和右子表,( )直到滿足條件scanUp>=scanDown,然後scanDown所在位置就是中心元素500的最終位置,交換v[0]與v[scanDown)=v[5],第一次劃分層級的最終結果資料集為:400,150,300,450,350,500,800,550,650,900,此時得到的左子表為:400,150,300,450,350,右子表為:800,550,650,900

下一個劃分層級是處理上一層級產生的子表,按照相同的處理方法分別處理左子表和右子表,左子表索引位置[0,5),右子表索引位置[6,10),按照上面的處理步驟處理左子表(400,150,300,450,350)得到的最終結果為:150,300,400,450,350 右子表最終處理結果為:550,650,800,900 在處理結果中300與650分別是中心值,他們現在的位置就是最終位置

在接下來的處理中,總是處理上一步驟中留下的子表,當子表數目<=1的時候就不用處理子表了,而子表有兩個元素的時候,比較大小,然後交換兩元素位置即可。

大於2個元素的子表都和上面的處理步驟一樣,我們將上面的處理過程編寫出一個函數

private int PivotIndex(int[] v, int first, int last),那麼快速排序演算法就是對此函數的遞迴調用

 

 /**//// <summary>
       /// 交換位置
       /// </summary>
       /// <param name="v"></param>
       /// <param name="index1"></param>
       /// <param name="index2"></param>
       private void Swrap(int[] v, int index1, int index2)
       {
           int temp = v[index1];
           v[index1] = v[index2];
           v[index2] = temp;
       }
       /**//// <summary>
       /// 將向量V中索引{first,last)劃分成兩個左子表和右子表
       /// </summary>
       /// <param name="v">向量V</param>
       /// <param name="first">開始位置</param>
       /// <param name="last">結束位置</param>
       private int PivotIndex(int[] v, int first, int last)
       {
           if (last == first)
           {
               return last;
           }
           if (last - first == 1)
           {
               return first;
           }
           int mid = (first + last) / 2;
           int midVal = v[mid];
           //交換v[first]和v[mid]
           Swrap(v, first, mid);
           int scanA = first + 1;
           int scanB = last - 1;
           for (; ; )
           { 

               while (scanA <= scanB && v[scanA] < midVal)
               {
                   scanA++;
               }
               while (scanB > first && midVal <= v[scanB])
               {
                   scanB--;
               }
               if (scanA >= scanB)
               {
                   break;
               }
               Swrap(v, scanA, scanB);
               scanA++;
               scanB--;
           }
           Swrap(v, first, scanB);
           return scanB; 

       }
       public void Sort(int[] v, int first, int last)
       {
           if (last - first <= 1)
           {
               return;
           }
           if (last - first == 2)
           {
               //有兩個元素的子表
               if (v[first] > v[last - 1])
               {
                   Swrap(v, first, last - 1);
               }
               return;
           }
           else
           {
               int pivotIndex = PivotIndex(v, first, last);
               Sort(v, first, pivotIndex);
               Sort(v, pivotIndex + 1, last);
           }
       } 

      快速排序因為每次劃分都能將中心值元素找到最終的位置,並且左邊值都小於中心值,右邊都大於中心值,它的時間複雜度平均和歸併演算法一致為O(nlog2n);

任何一種基於比較的排序演算法的時間複雜度不可能小於這個數,除非不使用比較的方法進行排序。

演算法程式:/Files/jillzhang/QuickSort.rar

上兩片第歸演算法學習:

1) 遞迴演算法學習系列一(分而治之策略)
2) 遞迴演算法學習系列二(歸併排序)

-------------------------------------------------------
人老了,腦袋不好用了,偶爾用演算法來練練腦子,可以防止早衰。呵呵
                                                        jillzhang jillzhang@126.com

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.