基數(cardinality)排序算法

基數排序是箱排序的改進和推廣。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章