日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C#數(shù)據(jù)結(jié)構(gòu)與算法揭秘19

 黃金屋1 2017-04-10

這節(jié),我們介紹基數(shù)排序和歸并排序。

一、基數(shù)排序

基數(shù)排序(Radix Sort)的設(shè)計(jì)思想與前面介紹的各種排序方法完全不同。前面介紹的排序方法主要是通過關(guān)鍵碼的比較和記錄的移動(dòng)這兩種操作來實(shí)現(xiàn)排序的,而基數(shù)排序不需要進(jìn)行關(guān)鍵碼的比較和記錄的移動(dòng)。基數(shù)排序是一種借助于多關(guān)鍵碼排序的思想,是將單關(guān)鍵碼按基數(shù)分成多關(guān)鍵碼進(jìn)行排序的方法,是一種分配排序。

下面用一個(gè)具體的例子來說明多關(guān)鍵碼排序的思想。
一副撲克牌有 52 張牌,可按花色和面值進(jìn)行分類,其大小關(guān)系如下:
花色:梅花<方塊<紅心<黑心
面值:2<3<4<5<6<7<8<9<10<J<Q<K<A
在對(duì)這 52 張牌進(jìn)行升序排序時(shí),有兩種排序方法:
方法一:可以先按花色進(jìn)行排序,將牌分為 4 組,分別是梅花組、方塊組、紅心組和黑心組,然后,再對(duì)這 4 個(gè)組的牌分別進(jìn)行排序。最后,把 4 個(gè)組連接起來即可。
方法二:可以先按面值進(jìn)行排序,將牌分為 13 組,分別是 2 號(hào)組、3 號(hào)組、4 號(hào)組、…、A 號(hào)組,再將這 13 組的牌按花色分成 4 組,最后,把這四組的牌連接起來即可。
設(shè)序列中有n個(gè)記錄,每個(gè)記錄包含d個(gè)關(guān)鍵碼{k1,k2,…,kd},序列有序指的對(duì)序列中的任意兩個(gè)記錄ri和rj(1≤i≤j≤n) ,(ki1, ki2,…, kid)<( kj1, kj2,…, kjd) 其中,k1稱為最主位關(guān)鍵碼,kd稱為最次位關(guān)鍵碼。

其中,k1稱為最主位關(guān)鍵碼,kd稱為最次位關(guān)鍵碼。

多關(guān)鍵碼排序方法按照從最主位關(guān)鍵碼到最次位關(guān)鍵碼或從最次位關(guān)鍵碼到最主位關(guān)鍵碼的順序進(jìn)行排序,分為兩種排序方法:
(1)最高位優(yōu)先法(MSD法) 。先按k1排序,將序列分成若干子序列,每個(gè)子序列中的記錄具有相同的k1值;再按k2排序,將每個(gè)子序列分成更小的子序列;然后,對(duì)后面的關(guān)鍵碼繼續(xù)同樣的排序分成更小的子序列,直到按kd排序分組分成最小的子序列后,最后將各個(gè)子序列連接起來,便可得到一個(gè)有序的序列。前面介紹的撲克牌先按花色再按面值進(jìn)行排序的方法就是MSD法。
(2)最次位優(yōu)先法(LSD法) 。先按kd排序,將序列分成若干子序列,每個(gè)子序列中的記錄具有相同的kd值; 再按kd-1排序, 將每個(gè)子序列分成更小的子序列;然后,對(duì)后面的關(guān)鍵碼繼續(xù)同樣的排序分成更小的子序列,直到按k1排序分組分成最小的子序列后,最后將各個(gè)子序列連接起來,便可得到一個(gè)有序的序列。前面介紹的撲克牌先按面值再花色按進(jìn)行排序的方法就是LSD法。

基數(shù)的源代碼如下:

復(fù)制代碼
//基數(shù)排序的方法
public int[] RadixSort(int[] ArrayToSort, int digit,int len)
        {
         
           // 從低位到高位的方法
            for (int k = 1; k <= digit; k++)
            {
                // 臨時(shí)的數(shù)組存儲(chǔ)里面的十進(jìn)制的排序的結(jié)果
                int[] tmpArray = new int[ArrayToSort.Length];

                
                //臨時(shí)的數(shù)組存儲(chǔ)計(jì)數(shù)的結(jié)果
                int[] tmpCountingSortArray = new int[len];

                //基數(shù)的數(shù)組1            
for (int i = 0; i < ArrayToSort.Length; i++)
{ //截取實(shí)際值 570-570/10*10 int tmpSplitDigit = ArrayToSort[i] / (int)Math.Pow(10, k - 1) - (ArrayToSort[i] / (int)Math.Pow(10, k)) * 10; tmpCountingSortArray[tmpSplitDigit] += 1; } for (int m = 1; m < 10; m++) { tmpCountingSortArray[m] += tmpCountingSortArray[m - 1]; } // 輸出的結(jié)果 for (int n = ArrayToSort.Length - 1; n >= 0; n--) { int tmpSplitDigit = ArrayToSort[n] / (int)Math.Pow(10, k - 1) - (ArrayToSort[n] / (int)Math.Pow(10, k)) * 10; tmpArray[tmpCountingSortArray[tmpSplitDigit] - 1] = ArrayToSort[n]; tmpCountingSortArray[tmpSplitDigit] -= 1; } // 拷貝排序的數(shù)組 for (int p = 0; p < ArrayToSort.Length; p++) { ArrayToSort[p] = tmpArray[p]; } } return ArrayToSort; } //雙層的循環(huán) 時(shí)間的復(fù)雜度是O(n2)
復(fù)制代碼

        如圖所示:

基數(shù)排序是穩(wěn)定的排序,時(shí)間的復(fù)雜度是O(n2).

二、歸并排序

歸并排序(merge Sort)主要是二路歸并排序。二路歸并排序的基本思想是:將兩個(gè)有序表合并為一個(gè)有序表。
假設(shè)順序表 sqList 中的 n 個(gè)記錄為 n 個(gè)長度為1的有序表,從第1個(gè)有序表開始,把相鄰的兩個(gè)有序表兩兩進(jìn)行合并成一個(gè)有序表,得到 n/2 個(gè)長度為2的有序表。如此重復(fù),最后得到一個(gè)長度為 n 的有序表。
一趟二路歸并排序算法的實(shí)現(xiàn)如下所示, 算法中記錄的比較代表記錄關(guān)鍵碼的比較,順序表中只存放了記錄的關(guān)鍵碼:

對(duì)于n個(gè)記錄的順序表,將這n個(gè)記錄看作葉子結(jié)點(diǎn),若將兩兩歸并生成的子表看作它們的父結(jié)點(diǎn), 則歸并過程對(duì)應(yīng)于由葉子結(jié)點(diǎn)向根結(jié)點(diǎn)生成一棵二叉樹的過程。所以,歸并趟數(shù)約等于二叉樹的高度減1,即log2n,每趟歸并排序記錄關(guān)鍵碼比較的次數(shù)都約為n/2,記錄移動(dòng)的次數(shù)為2n(臨時(shí)順序表的記錄復(fù)制到原順序表中記錄的移動(dòng)次數(shù)為n) 。 因此, 二路歸并排序的時(shí)間復(fù)雜度為O (nlog2n) 。
而二路歸并排序使用了n個(gè)臨時(shí)內(nèi)存單元存放記錄,所以,二路歸并排序算法的空間復(fù)雜度為O(n) 。歸并排序,如圖所示:

一趟二路歸并排序算法的實(shí)現(xiàn)如下所示, 算法中記錄的比較代表記錄關(guān)鍵碼的比較,順序表中只存放了記錄的關(guān)鍵碼,相應(yīng)的源代碼如下:

復(fù)制代碼
public void Merge(SeqList<int> sqList, int len) 
   { 
        int m = 0;                 //臨時(shí)順序表的起始位置 
int l1 = 0;                 //第1個(gè)有序表的起始位置 
        int h1;                    //第1個(gè)有序表的結(jié)束位置 
int l2;                    //第2個(gè)有序表的起始位置 
int h2;                     //第2個(gè)有序表的結(jié)束位置 
        int i = 0; 
int j = 0;  
 
        //臨時(shí)表,用于臨時(shí)將兩個(gè)有序表合并為一個(gè)有序表 
        SeqList<int> tmp = new SeqList<int>(sqList.GetLength()); 
 
       //歸并處理 
        while (l1 + len < sqList.GetLength()) 
       {    
           l2 = l1 + len;           //第2個(gè)有序表的起始位置 
           h1 = l2 - 1;             //第1個(gè)有序表的結(jié)束位置 
 
          //第2個(gè)有序表的結(jié)束位置 
           h2 = (l2 + len - 1 < sqList.GetLength())  
? l2 + len - 1 : sqList.Last; 
 
           j = l2; 
           i = l1; 
 
           //兩個(gè)有序表中的記錄沒有排序完 
           while ((i<=h1) && (j<=h2)) 
           { 
                //第1個(gè)有序表記錄的關(guān)鍵碼小于第2個(gè)有序表記錄的關(guān)鍵碼 
                if (sqList[i] <= sqList[j])     
                { 
                    tmp[m++] = sqList[i++]; 
                } 
                //第2個(gè)有序表記錄的關(guān)鍵碼小于第1個(gè)有序表記錄的關(guān)鍵碼
else 
                { 
                    tmp[m++] = sqList[j++]; 
                } 
            } 
 
            //第1個(gè)有序表中還有記錄沒有排序完 
            while (i <= h1) 
            { 
                tmp[m++] = sqList[i++]; 
            } 
 
            //第2個(gè)有序表中還有記錄沒有排序完 
            while (j <= h2) 
            { 
                tmp[m++] = sqList[j++]; 
            } 
 
            l1 = h2 + 1; 
        } 
 
        i = l1; 
        //原順序表中還有記錄沒有排序完 
        while (i < sqList.GetLength()) 
        { 
            tmp[m++] = sqList[i++]; 
        } 
 
        //臨時(shí)順序表中的記錄復(fù)制到原順序表,使原順序表中的記錄有序 
       for (i = 0; i < sqList.GetLength(); ++i) 
        { 
            sqList[i] = tmp[i]; 
} 
} 
二路歸并排序算法的實(shí)現(xiàn)如下: 
public void MergeSort(SeqList<int> sqList) 
     { 
          int k = 1;     //歸并增量 
 
          while (k < sqList.GetLength()) 
          { 
               Merge(sqList, k); 
               k *= 2; 
           }
  }
復(fù)制代碼

對(duì)于n個(gè)記錄的順序表,將這n個(gè)記錄看作葉子結(jié)點(diǎn),若將兩兩歸并生成的子表看作它們的父結(jié)點(diǎn), 則歸并過程對(duì)應(yīng)于由葉子結(jié)點(diǎn)向根結(jié)點(diǎn)生成一棵二叉樹的過程。所以,歸并趟數(shù)約等于二叉樹的高度減1,即log2n,每趟歸并排序記錄關(guān)鍵碼比較的次數(shù)都約為n/2,記錄移動(dòng)的次數(shù)為2n(臨時(shí)順序表的記錄復(fù)制到原順序表中記錄的移動(dòng)次數(shù)為n) 。 因此, 二路歸并排序的時(shí)間復(fù)雜度為O (nlog2n)。而二路歸并排序使用了n個(gè)臨時(shí)內(nèi)存單元存放記錄,所以,二路歸并排序算法的空間復(fù)雜度為O(n) 。

C#數(shù)據(jù)結(jié)構(gòu),就此結(jié)束了,這是我的一點(diǎn)總結(jié)。

 

 

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多