基數排序是箱排序的改進和推廣。
1、基數排序的基本思想
箱排序也稱爲桶排序(Bucket Sort),其基本思想是:設置若干箱子,依次掃描待排序的記錄R[0],R[1],R[2]...R[n],把關鍵字等於k的記錄全部裝入到第k個箱子裏(分配),然後按序號一次將各非空的箱子收尾連接起來(收集)。
例如,要將一副混洗的52張撲克牌按點數A<2<...<J<Q<K排序,需設置13個"箱子",排序時一次將每張牌按點數放入相應的箱子裏,然後依次將這些箱子首尾相連,就得到按點數遞增順序排序的一副牌。
基數排序是基於多關鍵字的,什麼是多關鍵字的呢?如果文件中任何一個記錄R[i]的關鍵字都由d個分量構成,而且這d個分量中每個分量都是一個獨立的關鍵字,則文件是多關鍵字的(比如撲克牌的兩個關鍵字:點數和花色)。
通常實現多關鍵字的排序有兩種方法:
最高位優先和最低位優先。
基數排序是典型的LSD排序方法,其基本思想是:從低位到高位依次對數據進行箱排序。在d趟箱排序中,所需的箱子書就是基數rd(可能的取值個數),這就是"基數排序"名稱的由來。
2、思想
它是一種非比較排序。它是根據位的高低進行排序的,也就是先按個位排序,然後依據十位排序……以此類推。示例如下:
3、算法複雜度
分配需要O(n),收集爲O(r),其中r爲分配後鏈表的個數,以r=10爲例,則有0~9這樣10個鏈表來將原來的序列分類。而d,也就是位數(如最大的數是1234,位數是4,則d=4),即"分配-收集"的趟數。因此時間複雜度爲O(d*(n+r))。
4、穩定性
基數排序過程中不改變元素的相對位置,因此是穩定的!
5、代碼實現
//使用基數排序對整數進行排序
//基數排序是複雜排序,適用於知道範圍數據例如1-1000進行排序
//1.首先定義一個10個大小的指針數組,每個指針表示一個箱子,指針用於操作每個箱子
//2.在定義一個10個大小的數組,數組每個位置用於存儲每個箱子裝有多少元素
//3.找出數組中最大整數,得到最大整數的位數(每次除以10,記數++,直到number等於0爲止)
//4.爲指針數組中的指針開闢內存空間,並初始化爲0
//5.以最小位數開始遍歷,每次遍歷之前清空記數數組(count)
//6.內層循環遍歷數組a[0]-a[length-1],每次取得數組中元素第i位的數字xx,將元素放入數組xx中的第count[xx]位置,同時記數數組相應的數據++
//7.把所有數據存放到temp中之後,需按同位大小取出元素,根據count記數中每個記錄的個數取出temp中所有元素.
//8.index=0,是從原始數組的a[0]開始,若記數爲0的話,直接跳過取下一個箱子的元素(最內層循環體爲a[index++]=temp[j][k],取出箱子每個元素放入a數組中)
//循環5-8步驟,直至最大值的最大位數循環完畢。
#include<iostream>
using namespace std;
//查找長度爲length的數組的最大元素
int find_max(int a[], int length)
{
int max = a[0]; //max從a[0]開始
for (int i = 1; i < length; i++)
{
if (max<a[i]) //如果發現元素比max大,就重新給max賦值
{
max = a[i];
}
}
return max;
}
//計算number有多少位
static int digit_number(int number)
{
int digit = 0;
do
{
number /= 10; //除以10,記數+1
digit++;
} while (number!=0); //直到等於0爲止
return digit;
}
//返回number上地Kth位的數字
static int kth_digit(int a, int i)
{
int num = a/pow(10, i); //除以10的幾次方,取餘
return num%10;
}
//對長度爲length的數組進行基數排序
static void radix_sort(int a[], int length)
{
int* temp[10]; //指針數組,每一個指針表示一個箱子
int i, j, k;
int count[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //用於存儲每個箱子裝有多少元素
int max = find_max(a, length); //取得數組中的最大整數
int digitNum = digit_number(max); //得到最大整數的位數
for (i = 0; i < 10; i++)
{
temp[i] = new int[length]; //是每一個箱子能裝下length個int元素
memset(temp[i], 0, sizeof(int)*length); <span style="white-space:pre"> </span>//初始化爲0
}
for (i = 0; i < digitNum; i++) //循環幾位數次
{
memset(count, 0, sizeof(int)* 10); //每次裝箱前把count記數數組清空
for (j = 0; j < length; j++)
{
int xx = kth_digit(a[j], i); //取得每位數
temp[xx][count[xx]] = a[j]; //將位數放入到對應的暫存數組中
count[xx]++; //此對應的箱子記數遞增
}
int index = 0;
for (j = 0; j < 10; j++) //取出所有箱子中的元素,將數據從暫存數組中取回
{
for (k = 0; k < count[j]; k++) <span style="white-space:pre"> </span>//把箱子裏所有的 元素都去回到原始數組中
{
a[index++] = temp[j][k];
}
}
}
}
static void print_array(int a[], int length)
{
for (int i = 0; i < length; i++) //打印數組
{
cout << a[i] << " ";
}
}
void main9mianshiti8()
{
int a[] = { 22, 32, 19, 53, 47, 29 };
cout << "before print_array: ";
print_array(a, 6);
radix_sort(a, 6); //基數排序
cout << "\nafter print_array: ";
print_array(a, 6);
system("pause");
}
6、測試結果
before print_array:22 32 19 53 47 29
after print_array:19 22 29 32 47 53