基数排序负数处理

基数排序算法很简单,实现起来也没有什么难度,基于数位的桶分配,过程在分配和收集之间进行。看了看别人的算法,对于负数的处理都不太满意,于是自己改了改算法。之前看有人又分配了10个桶给负数,但是这样会很损耗空间,数据大的时候容易超时。最好是负数不用单独处理,于是在计算数位的时候,有了如下公式:

key = (Number/((int)pow(10,shuwei)))%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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值