基数排序算法很简单,实现起来也没有什么难度,基于数位的桶分配,过程在分配和收集之间进行。看了看别人的算法,对于负数的处理都不太满意,于是自己改了改算法。之前看有人又分配了10个桶给负数,但是这样会很损耗空间,数据大的时候容易超时。最好是负数不用单独处理,于是在计算数位的时候,有了如下公式:
数位最低位为0(个位),依次递增,则key为Number第shuwei的值,结果显示上述公式对于负数的计算结果和正数只是相差一个负号。
刚开始想的是正数收集一遍,负数在倒着收集一遍,但是这样就要遍历两次链表数组,结果还要组合起来。最后想到可以计算负数的个数,在最后排序的数组中,负数总在前,于是找到分界,在一次收集的过程中,负数向前插入,非负数向后插入,最后组成完整数组。代码如下:
#include "math.h"
#include "stdlib.h"
const int max = 10;
typedef struct bucketNode{
int data;
struct bucketNode* next;
struct bucketNode* tail;
}bucketNode;
//初始化桶
void initBucket(bucketNode bucket[]) {
for(int i=0;i<10;i++){
bucket[i].data = -1;
bucket[i].next = NULL;
bucket[i].tail = NULL;
}
}
void allocate(int arr[],int n) {
bucketNode bucket[10];
initBucket(bucket);
int fuNum = 0; //负数个数
int sign = 1; //数位标志,当现位为不0,置为1
int shuwei = 0; //数位,初始为0(个位)
for(int i=0;i<n;i++){
if(arr[i]<0){
fuNum++;
}
}
//判断当前数位是否还有高位
while(sign != 0) {
sign = 0;
//分配
for(int i=0;i<n;i++){
int key = (arr[i]/((int)pow(10,shuwei)))%10;
// 处理负值
if(key <0){
key = -key;
}
//高数位标志
if(key != 0){
sign = 1;
}
bucketNode *bNode = (bucketNode *)malloc(sizeof(bucketNode));
bNode->data = arr[i];
bNode->next = NULL;
//将结点插入链表
if(bucket[key].tail == NULL){
bucket[key].next = bNode;
bucket[key].tail = bNode;
}else{
bucket[key].tail->next = bNode;
bucket[key].tail = bNode; //更新尾指针
}
}
//输出链表
for(int i=0;i<max;i++){
printf("%d: ",i);
bucketNode *p = bucket[i].next;
while(p!=NULL){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
//收集
int num =fuNum;
int fnum = 0;
for(int i=0;i<max;i++){
bucketNode *p,*q;
p=bucket[i].next;
while(p!=NULL){
if(p->data >=0){
arr[num] = p->data;
num++;
}else{
arr[fnum] = p->data;
fnum++;
}
q=p;
p = q->next;
free(q); //释放结点
}
bucket[i].next =NULL;
bucket[i].tail = NULL;
}
shuwei++;
for(int i=0;i<max;i++){
printf("%d ",arr[i]);
}
printf("\n");
}
//重排负数
for(int i = 0;i<fuNum/2;i++){
int temp = arr[i];
arr[i] = arr[fuNum-i-1];
arr[fuNum-i-1] = temp;
}
}