# 手寫基數排序算法

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基數排序（Radix sort）是一種非比較型整數排序算法，其基本思想爲：","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個待排序整數序列，將其中每個整數看成由不同位構成(比如，個位十位百位千位...)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以先按個位的數值，將這些數分配到0~9的10個桶中，然後再按從0到9的順序把這些數從10個桶中收集回來，這時這些數就已經按照個位排好序了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後再按照10位上的數值，把這些數分配到10個桶中，分配完畢後再次收集回來，這時這些數就已經按照十位和個位排好序了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再按百位、千位依次進行上述過程，直到排序的位數到達數列中最大數的最高位，則排序結束。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於計算機中字符、浮點等都是由整數來表示的，因此基數排序算法是一種普適性的算法，可以用於整數、字符、浮點數排序。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基數排序算法的核心過程，包括：","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"計算出待排序數列的最大值 max","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"計算出最大值的最高位位數 div_cnt","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"分配內存，代表0~9的10個桶，用於存儲數據","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"循環div_cnt 次，每次根據一個分位(個位,十位,百位...)，將這些數據分配到桶中，然後再按桶的順序將數據收集回來。循環結束後，數據就已經是排好序的了。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"釋放內存。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基數排序，用一個例子來圖解說明：","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"待排序數列：36, 341, 45, 8, 257","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"準備10個桶，存儲從0到9的分位值：","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/39/3952291d6fa863b49b6abe2792f35ae1.jpeg","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先將每個整數，按個位上的值，分配到對應的桶中：","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/26/26dd4153d6370898e1a2196d37ef85fa.jpeg","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從桶中將數據收集回來，得到的數列爲：341， 45， 36， 257， 8","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再將每個整數，按十分位上的值，分配到對應的桶中：","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f7/f7d513e35f1df6a05f151bf878e86a20.jpeg","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從桶中將數據收集回來：8，36， 341， 45， 257","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再將每個整數，按百分位上的值，分配到對應的桶中：","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/44/44b44d05fe7c9480b71ad4df579cc3be.jpeg","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從桶中將數據收集回來：8，36， 45， 257，341","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於百分位是最大數的最高位，因此排序結束。最終的​排序結果是：8，36， 45， 257，341","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基數排序, 用C 語言實現的代碼如下：","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(ivec_t 是動態變長數組，存儲integer 數據。類似c++中的vector，代碼實現見後面)","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"c"},"content":[{"type":"text","text":"void radix_sort(int* parr, int count) {\n // 1. compute maximum value\n int max = parr[0];\n for (int i = 1; i < count; i++) {\n if (parr[i] > max) {\n max = parr[i];\n }\n }\n\n // 2. computer div_cnt\n int div_cnt = 0;\n int max_temp = max;\n while (max_temp > 0) {\n max_temp /= 10;\n div_cnt++;\n }\n\n // 3. alloc memory for sorting\n ivec_t* pvecs = (ivec_t*)malloc(10 * sizeof(ivec_t));\n for (int i = 0; i < 10; i++) {\n ivec_init(pvecs + i, 8);\n }\n\n // 4. sort\n int divisor = 1;\n for (int k = 0; k < div_cnt; k++) {\n // clear memory\n for (int i = 0; i < 10; i++) {\n ivec_clear(pvecs + i);\n }\n\n // distribute to ivec\n for (int i = 0; i < count; i++) {\n int idx = (parr[i] / divisor) % 10;\n ivec_append(pvecs + idx, parr[i]);\n }\n divisor *= 10;\n\n // collect from ivec\n int idx = 0;\n for (int i = 0; i < 10; i++) {\n int* pbuf = ivec_buf(pvecs + i);\n int cnt = ivec_len(pvecs + i);\n for (int n = 0; n < cnt; n++) {\n parr[idx++] = pbuf[n];\n }\n }\n }\n\n // 5. free memory\n for (int i = 0; i < 10; i++) {\n ivec_destroy(pvecs + i);\n }\n free(pvecs);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述代碼中，使用了 ivec_t 這樣的數據結構及相關函數，實現對桶的數據管理。ivec_t 的實現代碼如下：","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"c"},"content":[{"type":"text","text":"typedef struct ivec_t {\n int cap;\n int len;\n int* pbuf;\n} ivec_t;\n\nint ivec_init(ivec_t* pvec, int cap);\nint ivec_append(ivec_t* pvec, int val);\nint ivec_len(ivec_t* pvec);\nint* ivec_buf(ivec_t* pvec);\nvoid ivec_clear(ivec_t* pvec);\nint ivec_destroy(ivec_t* pvec);\n\nint ivec_init(ivec_t* pvec, int cap) {\n pvec->len = 0;\n pvec->cap = cap;\n pvec->pbuf = (int*)malloc(cap * sizeof(int));\n return 0;\n}\n\nint ivec_append(ivec_t* pvec, int val) {\n if (pvec->len >= pvec->cap) { // need expand\n int new_cap = pvec->cap * 2;\n int* pnew_buf = realloc(pvec->pbuf, new_cap * sizeof(int));\n if (!pnew_buf) {\n return -1;\n }\n\n pvec->pbuf = pnew_buf;\n pvec->cap = new_cap;\n }\n\n pvec->pbuf[pvec->len++] = val;\n return 0;\n}\n\nint ivec_len(ivec_t* pvec) {\n return pvec->len;\n}\n\nint* ivec_buf(ivec_t* pvec) {\n return pvec->pbuf;\n}\n\nvoid ivec_clear(ivec_t* pvec) {\n pvec->len = 0;\n}\n\nint ivec_destroy(ivec_t* pvec) {\n free(pvec->pbuf);\n memset(pvec, 0, sizeof(*pvec));\n return 0;\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​我的微信號是 實力程序員，歡迎大家轉發至朋友圈，分享給更多的朋友。","attrs":{}}]}]}