基数排序 radix sort

基数排序

  • 时间复杂度:平均、最好、最坏都为O(k*n),其中k为常数,n为元素个数
  • 空间复杂度:O(n+k)
  • 稳定性:稳定

算法解析:

  • 基数排序的思想就是先排好各位,然后排好各位的基础上排十位,以此类推,直到遍历最高位 次,排序结束(仔细理解最后一句话)
  • 基数排序不是比较排序,而是通过分配和收集的过程来实现排序
  • 初始化10个桶(固定的),桶下标为0-9
  • 通过得到待排序数字的个十百等位的数字,把这个数字对应的item放到对应的桶中
  • 基数排序有两种排序方式:LSD和MSD,最小位优先(从右边开始)和最大位优先(从左边开始)

动画演示

radixSort.gif

OC代码实现 LSD

- (void)radixSort:(NSMutableArray *)arr {// [@1,@2,@19,...]
    
    NSNumber *max = arr[0];
    for (NSNumber *num in arr) {
        if ([num intValue] > [max intValue]) {
            max = num;
        }
    }
    int position = 0;
    int maxDigital = [max intValue];
    while (maxDigital > 0) {
        maxDigital /= 10;
        position++;
    }
    NSMutableArray *arrMutable = [NSMutableArray array];
    for (int i = 0; i<10; i++) {
        [arrMutable addObject:[NSMutableArray array]];
    }
    
    int divisor = 1;//除数
    for (int i = 0; i<position; i++) {
        for (NSNumber *n in arr) {
            int digital = [n intValue];
            int lastN = (digital/divisor)%10;
            [((NSMutableArray *)arrMutable[lastN]) addObject:n];
        }
        int increase = 0;
        for (int j = 0; j<arrMutable.count; j++) {
            for (int k = 0; k<((NSArray *)arrMutable[j]).count; k++) {
                arr[increase] = arrMutable[j][k];
                increase++;
            }
        }
        [arrMutable makeObjectsPerformSelector:@selector(removeAllObjects)];
        divisor *= 10;
    }
}

Swift实现 LSD

func radixSort(arr : inout [Int]) -> Void {
    //0-9,10个桶
    var bucket = [[Int]]()
    for _ in 0..<10 {
        bucket.append([Int]())
    }
    //获取最大值
    var max = 0
    for (_,item) in arr.enumerated() {
        if max < item {
            max = item
        }
    }
    //获取最高位
    var position = 0
    while max > 0 {
        max = max / 10
        position += 1
    }

    var divisor = 1
    var num = 0//位上的数字
    for _ in 0..<position {
        for (_,item) in arr.enumerated() {//入桶
            num = (item / divisor) % 10
            bucket[num].append(item)
        }
        //遍历完成,需要重置arr
        var k = 0
        for i in 0..<bucket.count {//把有数据的桶串起来
            while !bucket[i].isEmpty {
                arr[k] = bucket[i].remove(at: 0)
                k += 1
            }
        }
        divisor = divisor * 10 //位:1 10 100
    }
}

以下代码实现均来源于网络,未验证

c++实现

/*
*求数据的最大位数,决定排序次数
*/
int maxbit(int data[], int n) 
{
    int d = 1; //保存最大的位数
    int p = 10;
    for(int i = 0; i < n; ++i)
    {
        while(data[i] >= p)
        {
            p *= 10;
            ++d;
        }
    }
    return d;
}
void radixsort(int data[], int n) //基数排序
{
    int d = maxbit(data, n);
    int tmp[n];
    int count[10]; //计数器
    int i, j, k;
    int radix = 1;
    for(i = 1; i <= d; i++) //进行d次排序
    {
        for(j = 0; j < 10; j++)
            count[j] = 0; //每次分配前清空计数器
        for(j = 0; j < n; j++)
        {
            k = (data[j] / radix) % 10; //统计每个桶中的记录数
            count[k]++;
        }
        for(j = 1; j < 10; j++)
            count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
        for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
        {
            k = (data[j] / radix) % 10;
            tmp[count[k] - 1] = data[j];
            count[k]--;
        }
        for(j = 0; j < n; j++) //将临时数组的内容复制到data中
            data[j] = tmp[j];
        radix = radix * 10;
    }

JavaScript 代码实现

var counter = [];
function radixSort(arr, maxDigit) {
    var mod = 10;
    var dev = 1;
    for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        for(var j = 0; j < arr.length; j++) {
            var bucket = parseInt((arr[j] % mod) / dev);
            if(counter[bucket]==null) {
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);
        }
        var pos = 0;
        for(var j = 0; j < counter.length; j++) {
            var value = null;
            if(counter[j]!=null) {
                while ((value = counter[j].shift()) != null) {
                      arr[pos++] = value;
                }
          }
        }
    }
    return arr;
}

Java 代码实现

public class RadixSort {
private static void radixSort(int[] array,int d)
{
    int n=1;//代表位数对应的数:1,10,100...
    int k=0;//保存每一位排序后的结果用于下一位的排序输入
    int length=array.length;
    int[][] bucket=new int[10][length];//排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
    int[] order=new int[length];//用于保存每个桶里有多少个数字
    while(n<d)
    {
        for(int num:array) //将数组array里的每个数字放在相应的桶里
        {
            int digit=(num/n)%10;
            bucket[digit][order[digit]]=num;
            order[digit]++;
        }
        for(int i=0;i<length;i++)//将前一个循环生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果
        {
            if(order[i]!=0)//这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
            {
                for(int j=0;j<order[i];j++)
                {
                    array[k]=bucket[i][j];
                    k++;
                }
            }
            order[i]=0;//将桶里计数器置0,用于下一次位排序
        }
        n*=10;
        k=0;//将k置0,用于下一轮保存位排序结果
    }
}

php实现

function radixSort($arr, $maxDigit = null)
{
    if ($maxDigit === null) {
        $maxDigit = max($arr);
    }
    $counter = [];
    for ($i = 0; $i < $maxDigit; $i++) {
        for ($j = 0; $j < count($arr); $j++) {
            preg_match_all('/\d/', (string) $arr[$j], $matches);
            $numArr = $matches[0];
            $lenTmp = count($numArr);
            $bucket = array_key_exists($lenTmp - $i - 1, $numArr)
                ? intval($numArr[$lenTmp - $i - 1])
                : 0;
            if (!array_key_exists($bucket, $counter)) {
                $counter[$bucket] = [];
            }
            $counter[$bucket][] = $arr[$j];
        }
        $pos = 0;
        for ($j = 0; $j < count($counter); $j++) {
            $value = null;
            if ($counter[$j] !== null) {
                while (($value = array_shift($counter[$j])) !== null) {
                    $arr[$pos++] = $value;
                }
          }
        }
    }

    return $arr;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容

  • 基本思想: 基数排序是一种有意思的排序,在看过其它比较排序后,基数排序真的很有意思。 基数排序(Radix Sor...
    NEXTFIND阅读 17,478评论 1 10
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,258评论 0 2
  • 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序...
    Awanwan阅读 563评论 0 0
  • 一些概念 该算法是稳定的排序法; 在所有的情况下,时间复杂度均为O(nlog(p)k),空间复杂度为O(n*p)(...
    假装会编程阅读 1,046评论 0 0
  • 加入好报画画群,到明天的话就整整满一个月了,像学生一样到了毕业季,是需要交纳一篇毕业作品的,丢丢老师建议将之前的作...
    一心小茶馆阅读 1,119评论 6 18