/*
基数排序:
含义:用在卡片机上的排序算法。
特点:从最低位进行排序,稳定,d位数需要d趟
适用:对年月日的排序
引理:n个d位数,每个数有k个可能的取值,基数排序采用稳定排序。耗时O(d(n+k))
证明:共需要d趟,每趟对n个数排序,采用基数排序O(n+k),
因此总共需要O(d(n+k))
第一行的数n表示共有n个数字
第二行为n个数
输入:
7
329 457 657 839 436 720 355
输出:
329 355 436 457 657 720 839
*/
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std;
const int MAXSIZE = 10000;
//获取数字iNum中第d位数字,如果没有肯定返回0
int getDigit(int iNum,int d)
{
int iResult;
int iCount = 0;
do{
if(iCount == d)
{
break;
}
iResult = iNum % 10;
iNum = iNum / 10;
iCount += 1;
}while(iNum != 0);
//如果还没有到达第d位,说明该数没有第d位,则直接返回0
if(iCount < d)
{
return 0;
}
else
{
return iResult;
}
}
//计算最高位数d,123 / 10 = 12,余3,12/10=1余2,1/10=0采用除10取余直到除尽的方法
int digitNum(int iNum)
{
int iDigitNum = 0;
do{
iNum = iNum / 10;
iDigitNum += 1;
}while(iNum != 0);
return iDigitNum;
}
void print(int* pArr , int n)
{
for(int i = 0 ; i < n ; i++)
{
cout << pArr[i] << " ";
}
}
//计数排序,d表示第d趟
void countSort(int* pArr,int n,int k)
{
int* cArr = new int[k+1];
int* bArr = new int[n];
//初始化和计数
for(int i = 0; i <= k ; i++)
{
cArr[i] = 0;
}
for(int i = 0 ; i < n ; i++)
{
cArr[ pArr[i] ] += 1;
}
//确定摆放位置
for(int i = 1 ;i <= k ; i++)
{
cArr[i] += cArr[i-1];
}
//将计数结果输入到临时数组中
for(int i = n -1 ; i >= 0 ; i--)
{
//注意位置是从0开始的,需要减1
bArr[ cArr[ pArr[i] ] - 1 ] = pArr[i];
//摆放位置减一,防止出现重复元素
cArr[ pArr[i] ] -= 1;
}
//将结果写回原数组中
for(int i = 0 ; i < n; i++)
{
pArr[i] = bArr[i];
}
delete[] cArr;
delete[] bArr;
}
//基数排序,共需d趟,每趟时间O(n+k),每i趟先计算出各个数字的第i个低位,然后排序,这是数位上的数字需要和原数字建立联系
//最难的就是如何将数位上的数和原数字建立联系,因为计数排序肯定只能对,可以直接用就行,需要一个桶vector<>存放某一趟以某个数字结尾的数字,
void radixSort(int* pArr , int n, int d)
{
for(int i = 1 ; i <= d ; i++)
{
//按照第i位,塞入到对应的桶中,因为0~9,所以需要10个桶
vector< vector<int> > vecBucket;
for(int k = 0 ; k < 10 ; k++)
{
vector<int> vecTemp;
vecBucket.push_back(vecTemp);
}
//分解每个数字的第i位,并按照要求塞入到桶中,并将每个数字的第i位存储到数字中
int* aArr = new int[n];
for(int j = 0 ; j < n ; j++)
{
int digitNum = getDigit(pArr[j] , i);
//根据第i位上的数字,塞入到桶中
vecBucket[digitNum].push_back( pArr[j] );
aArr[j] = digitNum;
}
//对其进行计数排序
countSort(aArr , n , 9);
//根据计数排序结果和桶中的数字,逐步取出各个数字(逆序),然后再填入到原来的数组中
for(int k = n - 1 ; k >= 0 ; k--)
{
int a = aArr[k];
int num = vecBucket[a].back();
pArr[k] = num;
vecBucket[a].pop_back();
}
delete[] aArr;
}
print(pArr , n);
}
void process()
{
int n;
//int iArr[MAXSIZE];
while(cin >> n)
{
int maxNum = -1000;
int* pArr = new int[n];
for(int i = 0 ; i < n; i++)
{
cin >> pArr[i];
if(pArr[i] > maxNum)
{
maxNum = pArr[i];
}
}
int d = digitNum(maxNum);
radixSort(pArr , n, d);
delete[] pArr;
}
}
int main(int argc,char* argv[])
{
process();
getchar();
return 0;
}
算法导论:第8章 线性时间排序__基数排序
最新推荐文章于 2024-06-23 11:06:04 发布