基数排序
来源:互联网 发布:ubuntu dd u盘启动盘 编辑:程序博客网 时间:2024/06/05 00:26
今天写了个基数排序的程序,程序现在能运行了,但是里面还有很多地方可以优化,我会再出一个优化的版本的
主要可以优化的地方包含
1. 优化空间,现在需要排序的数据需要再申请一倍的空间用于存储临时数据。如果是一个对于空间要求高的地方,可以优化空间。优化空间,肯定会带来时间上的消耗。怎么优化空间,还没有具体想好,不过也有思路了。
2. 优化时间,现在代码中很多地方的检查其实可以进行剪枝,例如,SortByte函数,这里的循环理论上可以缩减。如果按照数组的大小按照现在是为8的话,可以由原来的8N减到4.5N。现在是按照16进制进行作为一个组,也可以改成256作为组。
实验结论:对1亿条数据进行排序测试,使用27s
测试程序也给出
main.c
#include <stdio.h>
#include <stdlib.h>
#include "RadixSort.h"
#include <time.h>
int main(int argc, char **argv)
{
int iLoop;
int *iArray;
//int iSize = 3;
int iSize = 100000000;
//int iSize = 50000;
iArray = (int *) malloc(sizeof(int) * iSize);
time_t tBegin, tEnd;
for(iLoop = 0; iLoop < iSize; iLoop++) {
iArray[iLoop] = rand();
}
time(&tBegin);
RadixSort(iArray, iSize);
time(&tEnd);
for(iLoop = 0; iLoop < iSize; iLoop++) {
printf("%d/n", iArray[iLoop]);
}
printf("%f/n",difftime(tEnd, tBegin));
return 0;
}
.h文件RadixSort.h
#ifndef _RADIX_SORT_H_
#define _RADIX_SORT_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void RadixSort(int * piArray, int iSize);
#endif
.c文件RadixSort.c
#include "RadixSort.h"
//获取iValue第iByteNum位的数据
static int GetByteValue(int iValue, int iByteNum)
{
return (iValue >> (4 * iByteNum)) & 0xf;
}
#define MAX_SIZE 8
//把iArray进行处理,按照计数排序的第二步处理那样
static void ArrayResort(int iArray[MAX_SIZE][16], int iMaxSize, int iGroupNum, int iSize)
{
int iLoop, jLoop;
int iOldValue;
int iOldTmp;
for(iLoop = 0; iLoop < iMaxSize; iLoop++) {
iOldValue = iArray[iLoop][iGroupNum - 1];
//这里从后面往前推,是为了去除那些GetByteValue的结果为0的个数不对的结果
//现在不存在这个问题,以前是在调用该函数的时候剪枝出现的问题。因为如果要提高速度还要进行剪枝,所以保留这里。
iArray[iLoop][iGroupNum - 1] = iSize - 1;
for(jLoop = iGroupNum - 2; jLoop >= 0; jLoop--) {
iOldTmp = iArray[iLoop][jLoop];
iArray[iLoop][jLoop] = iArray[iLoop][jLoop + 1] - iOldValue;
iOldValue = iOldTmp;
}
}
}
//把iByteInfo里面存储的byte数据,从pFrom复制到pTo里面,pFrom的大小为iSize,比较的是iByteIdx位
static void SortByte(int * pFrom, int *pTo, int iByteInfo[], int iByteIdx, int iSize)
{
int iLoop;
int iByteValue;
//这里使用从后面往前排,是为了不打乱以前排好的那部分数据
for(iLoop = iSize - 1; iLoop >= 0; iLoop--) {
iByteValue = GetByteValue(pFrom[iLoop], iByteIdx);
pTo[iByteInfo[iByteValue]] = pFrom[iLoop];
iByteInfo[iByteValue]--;
}
}
static void RadixSortPart(int * piArray, int iSize, int *pTmp)
{
int iArray[MAX_SIZE][16]; //存储基数排序的各个位上面对应值的个数
int iMaxSize;
int iTmpSize;
int *pSaveTmp; //保留哪一个是传进来的tmp
int *pFrom, *pMid, *pTo;
int iLoop, jLoop;
iMaxSize = 0; //最大的位数
memset(iArray, 0x00, sizeof(iArray));
for(iLoop = 0; iLoop < iSize; iLoop++) {
int iTmpValue;
iTmpSize = 0;
//从后面往前排的
for(jLoop = 0; jLoop < MAX_SIZE; jLoop++) {
iTmpValue = GetByteValue(piArray[iLoop], jLoop);
iArray[jLoop][iTmpValue]++;
}
if(jLoop > iMaxSize) {
iMaxSize = jLoop;
}
}
//数组计数排序累加过程
ArrayResort(iArray, iMaxSize, 16, iSize);
pFrom = piArray;
pTo = pTmp;
//循环排序,为了节省空间,把原始空间与新申请的空间来源作为from,to使用
for(iLoop = 0; iLoop < iMaxSize; iLoop++) {
SortByte(pFrom, pTo, iArray[iLoop], iLoop, iSize);
pMid = pFrom;
pFrom = pTo;
pTo = pMid;
}
//如果要最终结果没有存储在piArray中,要不最终的结果放到piArray中
if(pTo == piArray) {
for(iLoop = 0; iLoop < iSize; iLoop++) {
piArray[iLoop] = pTmp[iLoop];
}
}
}
//利用基数排序
void RadixSort(int * piArray, int iSize)
{
int *pA;
pA = (int *) malloc(iSize * sizeof(int));
if(pA == NULL) {
printf("malloc error:%s %d/n", __FILE__, __LINE__);
exit(-1);
}
RadixSortPart(piArray, iSize, pA);
free(pA);
}