算法导论:第8章 线性时间排序__基数排序

/*
基数排序:
含义:用在卡片机上的排序算法。
特点:从最低位进行排序,稳定,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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值