各種排序算法總結和比較


       排序算法可以說是一項基本功,解決實際問題中經常遇到,針對實際數據的特點選擇合適的排序算法可以使程序獲得更高的效率,有時候排序的穩定性還是實際問題中必須考慮的,這篇博客對常見的排序算法進行整理,包括:插入排序、選擇排序、冒泡排序、快速排序、堆排序、歸並排序、希爾排序、二叉樹排序、計數排序、桶排序、基數排序。

 

      代碼都經過了CodeBlocks的調試,但是很可能有沒注意到的BUG,歡迎指出。

 

      比較排序和非比較排序

      常見的排序算法都是比較排序,非比較排序包括計數排序、桶排序和基數排序,非比較排序對數據有要求,因為數據本身包含了定位特征,所有才能不通過比較來確定元素的位置。

      比較排序的時間復雜度通常為O(n2)或者O(nlogn),比較排序的時間復雜度下界就是O(nlogn),而非比較排序的時間復雜度可以達到O(n),但是都需要額外的空間開銷。

      比較排序時間復雜度為O(nlogn)的證明:

      a1,a2,a3……an序列的所有排序有n!種,所以滿足要求的排序a1',a2',a3'……an'(其中a1'<=a2'<=a3'……<=an')的概率為1/n!。基於輸入元素的比較排序,每一次比較的返回不是0就是1,這恰好可以作為決策樹的一個決策將一個事件分成兩個分支。比如冒泡排序時通過比較a1和a2兩個數的大小可以把序列分成a1,a2……an與a2,a1……an(氣泡a2上升一個身位)兩種不同的結果,因此比較排序也可以構造決策樹。根節點代表原始序列a1,a2,a3……an,所有葉子節點都是這個序列的重排(共有n!個,其中有一個就是我們排序的結果a1',a2',a3'……an')。如果每次比較的結果都是等概率的話(恰好划分為概率空間相等的兩個事件),那么二叉樹就是高度平衡的,深度至少是log(n!)。

      又因為 1. n! < nn ,兩邊取對數就得到log(n!)<nlog(n),所以log(n!) = O(nlogn).

                2. n!=n(n-1)(n-2)(n-3)…1 > (n/2)^(n/2) 兩邊取對數得到 log(n!) > (n/2)log(n/2) = Ω(nlogn),所以 log(n!) = Ω(nlogn)。

      因此log(n!)的增長速度與 nlogn 相同,即 log(n!)=Θ(nlogn),這就是通用排序算法的最低時間復雜度O(nlogn)的依據。

 

      排序的穩定性和復雜度

      不穩定:

      選擇排序(selection sort)— O(n2)

      快速排序(quicksort)— O(nlogn) 平均時間, O(n2) 最壞情況; 對於大的、亂序串列一般認為是最快的已知排序

      堆排序 (heapsort)— O(nlogn)

      希爾排序 (shell sort)— O(nlogn)

      基數排序(radix sort)— O(n·k); 需要 O(n) 額外存儲空間 (K為特征個數)

 

      穩定:

      插入排序(insertion sort)— O(n2)

      冒泡排序(bubble sort) — O(n2)

      歸並排序 (merge sort)— O(n log n); 需要 O(n) 額外存儲空間

      二叉樹排序(Binary tree sort) — O(nlogn); 需要 O(n) 額外存儲空間

      計數排序  (counting sort) — O(n+k); 需要 O(n+k) 額外存儲空間,k為序列中Max-Min+1

      桶排序 (bucket sort)— O(n); 需要 O(k) 額外存儲空間

 

      每種排序的原理和實現

      插入排序

      遍歷數組,遍歷到i時,a0,a1...ai-1是已經排好序的,取出ai,從ai-1開始向前和每個比較大小,如果小於,則將此位置元素向后移動,繼續先前比較,如果不小於,則放到正在比較的元素之后。可見相等元素比較是,原來靠后的還是拍在后邊,所以插入排序是穩定的。

      當待排序的數據基本有序時,插入排序的效率比較高,只需要進行很少的數據移動。

復制代碼
void insertion_sort (int a[], int n) {
    int i,j,v;
    for (i=1; i<n; i++) {
     //如果第i個元素小於第j個,則第j個向后移動
for (v=a[i], j=i-1; j>=0&&v<a[j]; j--) a[j+1]=a[j]; a[j+1]=v; } }
復制代碼

      選擇排序

      遍歷數組,遍歷到i時,a0,a1...ai-1是已經排好序的,然后從i到n選擇出最小的,記錄下位置,如果不是第i個,則和第i個元素交換。此時第i個元素可能會排到相等元素之后,造成排序的不穩定。

復制代碼
void selection_sort (int a[], int n) {
    int i,j,pos,tmp;
    for (i=0; i<n-1; i++) {
     //尋找最小值的下標
for (pos=i, j=i+1; j<n; j++) if (a[pos]>a[j]) pos=j; if (pos != i) { tmp=a[i]; a[i]=a[pos]; a[pos]=tmp; } } }
復制代碼

      冒泡排序

      冒泡排序的名字很形象,實際實現是相鄰兩節點進行比較,大的向后移一個,經過第一輪兩兩比較和移動,最大的元素移動到了最后,第二輪次大的位於倒數第二個,依次進行。這是最基本的冒泡排序,還可以進行一些優化。

      優化一:如果某一輪兩兩比較中沒有任何元素交換,這說明已經都排好序了,算法結束,可以使用一個Flag做標記,默認為false,如果發生交互則置為true,每輪結束時檢測Flag,如果為true則繼續,如果為false則返回。

      優化二:某一輪結束位置為j,但是這一輪的最后一次交換發生在lastSwap的位置,則lastSwap到j之間是排好序的,下一輪的結束點就不必是j--了,而直接到lastSwap即可,代碼如下:

復制代碼
void bubble_sort (int a[], int n) {
    int i, j, lastSwap, tmp;
    for (j=n-1; j>0; j=lastSwap) {
lastSwap=0; //每一輪要初始化為0,防止某一輪未發生交換,lastSwap保留上一輪的值進入死循環
for (i=0; i<j; i++) { if (a[i] > a[i+1]) { tmp=a[i]; a[i]=a[i+1]; a[i+1]=tmp;          //最后一次交換位置的坐標 lastSwap = i; } } } }
復制代碼

      快速排序

      快速排序首先找到一個基准,下面程序以第一個元素作為基准(pivot),然后先從右向左搜索,如果發現比pivot小,則和pivot交換,然后從左向右搜索,如果發現比pivot大,則和pivot交換,一直到左邊大於右邊,此時pivot左邊的都比它小,而右邊的都比它大,此時pivot的位置就是排好序后應該在的位置,此時pivot將數組划分為左右兩部分,可以遞歸采用該方法進行。快排的交換使排序成為不穩定的。

復制代碼
int mpartition(int a[], int l, int r) {
    int pivot = a[l];
</span><span style="color: #0000ff;">while</span> (l&lt;<span style="color: #000000;">r) {
    </span><span style="color: #0000ff;">while</span> (l&lt;r &amp;&amp; pivot&lt;=a[r]) r--<span style="color: #000000;">;
    </span><span style="color: #0000ff;">if</span> (l&lt;r) a[l++]=<span style="color: #000000;">a[r];
    </span><span style="color: #0000ff;">while</span> (l&lt;r &amp;&amp; pivot&gt;a[l]) l++<span style="color: #000000;">;
    </span><span style="color: #0000ff;">if</span> (l&lt;r) a[r--]=<span style="color: #000000;">a[l];
}
a[l]</span>=<span style="color: #000000;">pivot;
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> l;

}

void quick_sort (int a[], int l, int r) {

</span><span style="color: #0000ff;">if</span> (l &lt;<span style="color: #000000;"> r) {
    </span><span style="color: #0000ff;">int</span> q =<span style="color: #000000;"> mpartition(a, l, r);
    msort(a, l, q</span>-<span style="color: #800080;">1</span><span style="color: #000000;">);
    msort(a, q</span>+<span style="color: #800080;">1</span><span style="color: #000000;">, r);
}

}

復制代碼

       堆排序

       堆排序是把數組看作堆,第i個結點的孩子結點為第2*i+1和2*i+2個結點(不超出數組長度前提下),堆排序的第一步是建堆,然后是取堆頂元素然后調整堆。建堆的過程是自底向上不斷調整達成的,這樣當調整某個結點時,其左節點和右結點已經是滿足條件的,此時如果兩個子結點不需要動,則整個子樹不需要動,如果調整,則父結點交換到子結點位置,再以此結點繼續調整。

      下述代碼使用的大頂堆,建立好堆后堆頂元素為最大值,此時取堆頂元素即使堆頂元素和最后一個元素交換,最大的元素處於數組最后,此時調整小了一個長度的堆,然后再取堆頂和倒數第二個元素交換,依次類推,完成數據的非遞減排序。

      堆排序的主要時間花在初始建堆期間,建好堆后,堆這種數據結構以及它奇妙的特征,使得找到數列中最大的數字這樣的操作只需要O(1)的時間復雜度,維護需要logn的時間復雜度。堆排序不適宜於記錄數較少的文件

復制代碼
void heapAdjust(int a[], int i, int nLength)
{
    int nChild;
    int nTemp;
    for (nTemp = a[i]; 2 * i + 1 < nLength; i = nChild)
    {
        // 子結點的位置=2*(父結點位置)+ 1
        nChild = 2 * i + 1;
        // 得到子結點中較大的結點
        if ( nChild < nLength-1 && a[nChild + 1] > a[nChild])
            ++nChild;
        // 如果較大的子結點大於父結點那么把較大的子結點往上移動,替換它的父結點
        if (nTemp < a[nChild])
        {
            a[i] = a[nChild];
            a[nChild]= nTemp;
        }
        else
        // 否則退出循環
            break;
    }
}

// 堆排序算法
void heap_sort(int a[],int length)
{
int tmp;
// 調整序列的前半部分元素,調整完之后第一個元素是序列的最大的元素
//length/2-1是第一個非葉節點,此處"/"為整除
for (int i = length / 2 - 1; i >= 0; --i)
heapAdjust(a, i, length);
// 從最后一個元素開始對序列進行調整,不斷的縮小調整的范圍直到第一個元素
for (int i = length - 1; i > 0; --i)
{
// 把第一個元素和當前的最后一個元素交換,
// 保證當前的最后一個位置的元素都是在現在的這個序列之中最大的
/// Swap(&a[0], &a[i]);
tmp = a[i];
a[i]
= a[0];
a[
0] = tmp;
// 不斷縮小調整heap的范圍,每一次調整完畢保證第一個元素是當前序列的最大值
heapAdjust(a, 0, i);
}
}

復制代碼

       歸並排序

      歸並排序是采用分治法(Divide and Conquer)的一個非常典型的應用。首先考慮下如何將將二個有序數列合並。這個非常簡單,只要從比較二個數列的第一個數,誰小就先取誰,取了后就在對應數列中刪除這個數。然后再進行比較,如果有數列為空,那直接將另一個數列的數據依次取出即可。這需要將待排序序列中的所有記錄掃描一遍,因此耗費O(n)時間,而由完全二叉樹的深度可知,整個歸並排序需要進行.logn.次,因此,總的時間復雜度為O(nlogn)。

     歸並排序在歸並過程中需 要與原始記錄序列同樣數量的存儲空間存放歸並結果,因此空間復雜度為O(n)。

     歸並算法需要兩兩比較,不存在跳躍,因此歸並排序是一種穩定的排序算法。 

復制代碼
void mergearray(int a[], int first, int mid, int last, int temp[])
{
    int i = first, j = mid + 1;
    int m = mid,   n = last;
    int k = 0;
</span><span style="color: #0000ff;">while</span> (i &lt;= m &amp;&amp; j &lt;=<span style="color: #000000;"> n)
{
    </span><span style="color: #0000ff;">if</span> (a[i] &lt;=<span style="color: #000000;"> a[j])
        temp[k</span>++] = a[i++<span style="color: #000000;">];
    </span><span style="color: #0000ff;">else</span><span style="color: #000000;">
        temp[k</span>++] = a[j++<span style="color: #000000;">];
}

</span><span style="color: #0000ff;">while</span> (i &lt;=<span style="color: #000000;"> m)
    temp[k</span>++] = a[i++<span style="color: #000000;">];

</span><span style="color: #0000ff;">while</span> (j &lt;=<span style="color: #000000;"> n)
    temp[k</span>++] = a[j++<span style="color: #000000;">];

</span><span style="color: #0000ff;">for</span> (i = <span style="color: #800080;">0</span>; i &lt; k; i++<span style="color: #000000;">)
    a[first </span>+ i] =<span style="color: #000000;"> temp[i];

}
void merge_sort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
merge_sort(a, first, mid, temp);
//左邊有序
merge_sort(a, mid + 1, last, temp); //右邊有序
mergearray(a, first, mid, last, temp); //再將二個有序數列合並
}
}

復制代碼

      有的地方看到在mergearray()合並有序數列時分配臨時數組,即每一步mergearray的結果存放的一個新的臨時數組里,這樣會在遞歸中消耗大量的空間。因此做出小小的變化。只需要new一個臨時數組。后面的操作都共用這一個臨時數組。合並完后將臨時數組中排好序的部分寫回原數組。

      歸並排序計算時間復雜度時可以很容易的列出遞歸方程,也是計算時間復雜度的一種方法。

      希爾排序

      希爾排序是對插入排序的優化,基於以下兩個認識:1. 數據量較小時插入排序速度較快,因為n和n2差距很小;2. 數據基本有序時插入排序效率很高,因為比較和移動的數據量少。

      因此,希爾排序的基本思想是將需要排序的序列划分成為若干個較小的子序列,對子序列進行插入排序,通過則插入排序能夠使得原來序列成為基本有序。這樣通過對較小的序列進行插入排序,然后對基本有序的數列進行插入排序,能夠提高插入排序算法的效率。

      希爾排序的划分子序列不是像歸並排序那種的二分,而是采用的叫做增量的技術,例如有十個元素的數組進行希爾排序,首先選擇增量為10/2=5,此時第1個元素和第(1+5)個元素配對成子序列使用插入排序進行排序,第2和(2+5)個元素組成子序列,完成后增量繼續減半為2,此時第1個元素、第(1+2)、第(1+4)、第(1+6)、第(1+8)個元素組成子序列進行插入排序。這種增量選擇方法的好處是可以使數組整體均勻有序,盡可能的減少比較和移動的次數,二分法中即使前一半數據有序,后一半中如果有比較小的數據,還是會造成大量的比較和移動,因此這種增量的方法和插入排序的配合更佳。

      希爾排序的時間復雜度和增量的選擇策略有關,上述增量方法造成希爾排序的不穩定性。

 

      

復制代碼
void shell_sort(int a[], int n)
{
    int d, i, j, temp; //d為增量
    for(d = n/2;d >= 1;d = d/2) //增量遞減到1使完成排序
    {
        for(i = d; i < n;i++)   //插入排序的一輪
        {
            temp = a[i];
            for(j = i - d;(j >= 0) && (a[j] > temp);j = j-d)
            {
                a[j + d] = a[j];
            }
        a[j + d] = temp;
        }
    }
}
復制代碼

      二叉樹排序

      二叉樹排序法借助了數據結構二叉排序樹,二叉排序數滿足三個條件:(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; (2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; (3)左、右子樹也分別為二叉排序樹。根據這三個特點,用中序遍歷二叉樹得到的結果就是排序的結果。

      二叉樹排序法需要首先根據數據構建二叉排序樹,然后中序遍歷,排序時間復雜度為O(nlogn),構建二叉樹需要額外的O(n)的存儲空間,有相同的元素是可以設置排在后邊的放在右子樹,在中序變量的時候也會在后邊,所以二叉樹排序是穩定的。

      在實現此算法的時候遇到不小的困難,指針參數在函數中無法通過new賦值,后來采用取指針地址,然后函數設置BST** tree的方式解決。

復制代碼
int arr[] = {7, 8, 8, 9, 5, 16, 5, 3,56,21,34,15,42};

struct BST{
int number; //保存數組元素的值
struct BST left;
struct BST
right;
};

void insertBST(BST** tree, int v) {
if (tree == NULL) {
tree = new BST;
(
tree)->left=(tree)->right=NULL;
(
tree)->number=v;
return;
}
if (v < (
tree)->number)
insertBST(
&((tree)->left), v);
else
insertBST(
&((
tree)->right), v);
}

void printResult(BST* tree) {
if (tree == NULL)
return;
if (tree->left != NULL)
printResult(tree
->left);
cout
<< tree->number << " ";
if (tree->right != NULL)
printResult(tree
->right);
}

void createBST(BST** tree, int a[], int n) {
*tree = NULL;
for (int i=0; i<n; i++)
insertBST(tree, a[i]);
}

int main()
{
int n = sizeof(arr)/sizeof(int);

BST</span>*<span style="color: #000000;"> root;
createBST(</span>&amp;<span style="color: #000000;">root, arr, n);
printResult(root);

}

復制代碼

       計數排序

      如果通過比較進行排序,那么復雜度的下界是O(nlogn),但是如果數據本身有可以利用的特征,可以不通過比較進行排序,就能使時間復雜度降低到O(n)。

      計數排序要求待排序的數組元素都是 整數,有很多地方都要去是0-K的正整數,其實負整數也可以通過都加一個偏移量解決的。

      計數排序的思想是,考慮待排序數組中的某一個元素a,如果數組中比a小的元素有s個,那么a在最終排好序的數組中的位置將會是s+1,如何知道比a小的元素有多少個,肯定不是通過比較去覺得,而是通過數字本身的屬性,即累加數組中最小值到a之間的每個數字出現的次數(未出現則為0),而每個數字出現的次數可以通過掃描一遍數組獲得。

      計數排序的步驟:

  1. 找出待排序的數組中最大和最小的元素(計數數組C的長度為max-min+1,其中位置0存放min,依次填充到最后一個位置存放max)
  2. 統計數組中每個值為i的元素出現的次數,存入數組C的第i
  3. 對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加)
  4. 反向填充目標數組:將每個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1(反向填充是為了保證穩定性)

      以下代碼中尋找最大和最小元素參考編程之美,比較次數為1.5n次。

      計數排序適合數據分布集中的排序,如果數據太分散,會造成空間的大量浪費,假設數據為(1,2,3,1000000),這就需要1000000的額外空間,並且有大量的空間浪費和時間浪費。

復制代碼
void findArrMaxMin(int a[], int size, int *min, int *max)
{
    if(size == 0) {
        return;
    }
    if(size == 1) {
        *min = *max = a[0];
        return;
    }
</span>*min = a[<span style="color: #800080;">0</span>] &gt; a[<span style="color: #800080;">1</span>] ? a[<span style="color: #800080;">1</span>] : a[<span style="color: #800080;">0</span><span style="color: #000000;">];
</span>*max = a[<span style="color: #800080;">0</span>] &lt;= a[<span style="color: #800080;">1</span>] ? a[<span style="color: #800080;">1</span>] : a[<span style="color: #800080;">0</span><span style="color: #000000;">];


</span><span style="color: #0000ff;">int</span><span style="color: #000000;"> i, j;
</span><span style="color: #0000ff;">for</span>(i = <span style="color: #800080;">2</span>, j = <span style="color: #800080;">3</span>; i &lt; size, j &lt; size; i += <span style="color: #800080;">2</span>, j += <span style="color: #800080;">2</span><span style="color: #000000;">) {
    </span><span style="color: #0000ff;">int</span> tempmax = a[i] &gt;= a[j] ?<span style="color: #000000;"> a[i] : a[j];
    </span><span style="color: #0000ff;">int</span> tempmin = a[i] &lt; a[j] ?<span style="color: #000000;"> a[i] : a[j];

    </span><span style="color: #0000ff;">if</span>(tempmax &gt; *<span style="color: #000000;">max)
        </span>*max =<span style="color: #000000;"> tempmax;
    </span><span style="color: #0000ff;">if</span>(tempmin &lt; *<span style="color: #000000;">min)
        </span>*min =<span style="color: #000000;"> tempmin;
}

</span><span style="color: #008000;">//</span><span style="color: #008000;">如果數組元素是奇數個,那么最后一個元素在分組的過程中沒有包含其中,
</span><span style="color: #008000;">//</span><span style="color: #008000;">這里單獨比較</span>
<span style="color: #0000ff;">if</span>(size % <span style="color: #800080;">2</span> != <span style="color: #800080;">0</span><span style="color: #000000;">) {
    </span><span style="color: #0000ff;">if</span>(a[size -<span style="color: #800080;">1</span>] &gt; *<span style="color: #000000;">max)
        </span>*max = a[size - <span style="color: #800080;">1</span><span style="color: #000000;">];
    </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span>(a[size -<span style="color: #800080;">1</span>] &lt; *<span style="color: #000000;">min)
        </span>*min = a[size -<span style="color: #800080;">1</span><span style="color: #000000;">];
}

}

void count_sort(int a[], int b[], int n) {
int max, min;
findArrMaxMin(a, n,
&min, &max);
int numRange = max-min+1;
int* counter = new int[numRange];

</span><span style="color: #0000ff;">int</span><span style="color: #000000;"> i, j, k;
</span><span style="color: #0000ff;">for</span> (k=<span style="color: #800080;">0</span>; k&lt;numRange; k++<span style="color: #000000;">)
    counter[k]</span>=<span style="color: #800080;">0</span><span style="color: #000000;">;

</span><span style="color: #0000ff;">for</span> (i=<span style="color: #800080;">0</span>; i&lt;n; i++<span style="color: #000000;">)
    counter[a[i]</span>-min]++<span style="color: #000000;">;

</span><span style="color: #0000ff;">for</span> (k=<span style="color: #800080;">1</span>; k&lt;numRange; k++<span style="color: #000000;">)
    counter[k] </span>+= counter[k-<span style="color: #800080;">1</span><span style="color: #000000;">];

</span><span style="color: #0000ff;">for</span> (j=n-<span style="color: #800080;">1</span>; j&gt;=<span style="color: #800080;">0</span>; j--<span style="color: #000000;">) {
    </span><span style="color: #0000ff;">int</span> v =<span style="color: #000000;"> a[j];
    </span><span style="color: #0000ff;">int</span> index = counter[v-min]-<span style="color: #800080;">1</span><span style="color: #000000;">;
    b[index]</span>=<span style="color: #000000;">v;
    counter[v</span>-min]--<span style="color: #000000;">;
}

}

復制代碼

       桶排序

       假設有一組長度為N的待排關鍵字序列K[1....n]。首先將這個序列划分成M個的子區間(桶) 。然后基於某種映射函數 ,將待排序列的關鍵字k映射到第i個桶中(即桶數組B的下標 i) ,那么該關鍵字k就作為B[i]中的元素(每個桶B[i]都是一組大小為N/M的序列)。接着對每個桶B[i]中的所有元素進行比較排序(可以使用快排)。然后依次枚舉輸出B[0]....B[M]中的全部內容即是一個有序序列。

      桶排序利用函數的映射關系,減少了計划所有的比較操作,是一種Hash的思想,可以用在海量數據處理中。

      我覺得計數排序也可以看作是桶排序的特例,數組關鍵字范圍為N,划分為N個桶。

      基數排序

      基數排序也可以看作一種桶排序,不斷的使用不同的標准對數據划分到桶中,最終實現有序。基數排序的思想是對數據選擇多種基數,對每一種基數依次使用桶排序。

      基數排序的步驟:以整數為例,將整數按十進制位划分,從低位到高位執行以下過程。

      1. 從個位開始,根據0~9的值將數據分到10個桶桶,例如12會划分到2號桶中。

      2. 將0~9的10個桶中的數據順序放回到數組中。

      重復上述過程,一直到最高位。

      上述方法稱為LSD(Least significant digital),還可以從高位到低位,稱為MSD。

復制代碼
int getNumInPos(int num,int pos) //獲得某個數字的第pos位的值
{
    int temp = 1;
    for (int i = 0; i < pos - 1; i++)
        temp *= 10;
</span><span style="color: #0000ff;">return</span> (num / temp) % <span style="color: #800080;">10</span><span style="color: #000000;">;

}

#define RADIX_10 10 //十個桶,表示每一位的十個數字
#define KEYNUM 5 //整數位數
void radix_sort(int* pDataArray, int iDataNum)
{
int *radixArrays[RADIX_10]; //分別為0~9的序列空間
for (int i = 0; i < RADIX_10; i++)
{
radixArrays[i]
= new int[iDataNum];
radixArrays[i][
0] = 0; //index為0處記錄這組數據的個數
}

</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> pos = <span style="color: #800080;">1</span>; pos &lt;= KEYNUM; pos++)    <span style="color: #008000;">//</span><span style="color: #008000;">從個位開始到31位</span>

{
for (int i = 0; i < iDataNum; i++) //分配過程
{
int num = getNumInPos(pDataArray[i], pos);
int index = ++radixArrays[num][0];
radixArrays[num][index]
= pDataArray[i];
}

    </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = <span style="color: #800080;">0</span>, j =<span style="color: #800080;">0</span>; i &lt; RADIX_10; i++) <span style="color: #008000;">//</span><span style="color: #008000;">寫回到原數組中,復位radixArrays</span>

{
for (int k = 1; k <= radixArrays[i][0]; k++)
pDataArray[j
++] = radixArrays[i][k];
radixArrays[i][
0] = 0;
}
}
}

復制代碼

原文地址:https://www.cnblogs.com/zhaoshuai1215/p/3448154.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM