排序算法七:基数排序(Radix sort)
上一篇提到了计数排序,它在输入序列元素的取值范围较小时,表现不俗。但是,现实生活中不总是满足这个条件,比如最大整形数据可以达到231-1,这样就存在2个问题:
1)因为m的值很大,不再满足m=O(n),计数排序的时间复杂也就不再是线性的;
2)当m很大时,为计数数组申请的内存空间会很大;
为解决这两个问题,本篇讨论基数排序(Radix sort),基数排列的思想是:
1)将先按照某个基数将输入序列的每个元素划分成若干部分,每个部分对排序结果的影响是有优先级的;
2)先按低优先级排序,再按高优先级排序,依次递推。这里要注意,每个部分进行排序时,必须选用稳定排序算法,例如基数排序。
3)最后的次序就是高优先级高的在前,高优先级相同的,低优先级高的在前。
(一)算法实现
@Override
protected void sort(int[] toSort) {
// number to sort, n integers
int n = toSort.length;
// b bits each integer
int b = Integer.SIZE;
/*
* Split each integer into b/r digits, and each r bits long. So average
* running time is O(b/r(2^r+n)). It is proved that running time is
* close to least time while choosing r to lgn.
*/
int r = (int) Math.ceil(Math.log(n) / Math.log(2));
// considering the space cost, the maximum of r is 16.
r = Math.min(r, 16); int upperLimit = 1 << r;
int loopCount = b / r;
int j = 0;
int[] resultArray = new int[toSort.length];
int[] countingArray = new int[upperLimit];
while (j < loopCount) {
int rightShift = j * r;
radixSort(toSort, upperLimit, rightShift, resultArray,
countingArray);
Arrays.fill(countingArray, 0);
j++;
}
int mod = b % r;
if (mod != 0) {
upperLimit = 1 << mod;
int rightShift = r * loopCount;
countingArray = new int[upperLimit];
radixSort(toSort, upperLimit, rightShift, resultArray,
countingArray);
}
} private void radixSort(int[] toSort, int upperLimit, int rightShift,
int[] resultArray, int[] countingArray) {
int allOnes = upperLimit - 1;
for (int i = 0; i < toSort.length; i++) {
int radix = (toSort[i] >> rightShift) & allOnes;
countingArray[radix]++;
}
for (int i = 1; i < countingArray.length; i++) {
countingArray[i] += countingArray[i - 1];
} for (int i = toSort.length - 1; i >= 0; i--) {
int radix = (toSort[i] >> rightShift) & allOnes;
resultArray[countingArray[radix] - 1] = toSort[i];
countingArray[radix]--;
}
System.arraycopy(resultArray, 0, toSort, 0, resultArray.length);
}
radixSort
1)算法属于分配排序
2)平均时间复杂度是O(b/r(2r+n)), b-每个元素的bit数,r-每个元素划分成b/r个数字,每个数字r个bit。当r=log2n时,复杂度是O(2bn/log2n),也就是说,当b=O(log2n)时,时间复杂度是O(n).
3) 空间复杂度是O(2r+n)
4)算法属于稳定排序
(二)算法仿真
下面对随机化快速排序和基数排序,针对不同输入整数序列长度,仿真结果如下,从结果看,当输入序列长度越大,基数排序性能越优越。
**************************************************
Number to Sort is:2500
Array to sort is:{1642670374,460719485,1773719101,2140462092,1260791250,199719453,1290828881,1946941575,2032337910,643536338...}
Cost time of 【RadixSort】 is(milliseconds):48
Sort result of 【RadixSort】:{217942,491656,1389218,2642908,3608001,3976751,4905471,5094692,6340348,7693772...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):1
Sort result of 【RandomizedQuickSort】:{217942,491656,1389218,2642908,3608001,3976751,4905471,5094692,6340348,7693772...}
**************************************************
Number to Sort is:25000
Array to sort is:{987947608,1181521142,1240568028,373349221,289183678,2051121943,1257313984,745646081,1414556623,1859315040...}
Cost time of 【RadixSort】 is(milliseconds):1
Sort result of 【RadixSort】:{47434,109303,240122,255093,448360,526046,526445,628228,837987,966240...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):2
Sort result of 【RandomizedQuickSort】:{47434,109303,240122,255093,448360,526046,526445,628228,837987,966240...}
**************************************************
Number to Sort is:250000
Array to sort is:{1106960922,1965236858,1114033657,1196235697,2083563075,1994568819,1185250879,670222217,1386040268,1316674615...}
Cost time of 【RadixSort】 is(milliseconds):7
Sort result of 【RadixSort】:{466,884,8722,35382,37181,44708,53396,55770,67518,74898...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):27
Sort result of 【RandomizedQuickSort】:{466,884,8722,35382,37181,44708,53396,55770,67518,74898...}
**************************************************
Number to Sort is:2500000
Array to sort is:{1903738012,485657780,1747057138,2082998554,1658643001,91586227,2127717572,557705232,533021562,1322007386...}
Cost time of 【RadixSort】 is(milliseconds):81
Sort result of 【RadixSort】:{369,392,1316,1378,2301,3819,4013,4459,5922,6423...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):340
Sort result of 【RandomizedQuickSort】:{369,392,1316,1378,2301,3819,4013,4459,5922,6423...}
**************************************************
Number to Sort is:25000000
Array to sort is:{2145921976,298753549,11187940,410746614,503122524,1951513957,1760836125,2141838979,1702951573,1402856280...}
Cost time of 【RadixSort】 is(milliseconds):1,022
Sort result of 【RadixSort】:{130,145,406,601,683,688,736,865,869,954...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):3,667
Sort result of 【RandomizedQuickSort】:{130,145,406,601,683,688,736,865,869,954...}
相关源码:
package com.cnblogs.riyueshiwang.sort; import java.util.Arrays; public class RadixSort extends abstractSort { @Override
protected void sort(int[] toSort) {
// number to sort, n integers
int n = toSort.length;
// b bits each integer
int b = Integer.SIZE;
/*
* Split each integer into b/r digits, and each r bits long. So average
* running time is O(b/r(2^r+n)). It is proved that running time is
* close to least time while choosing r to lgn.
*/
int r = (int) Math.ceil(Math.log(n) / Math.log(2));
// considering the space cost, the maximum of r is 16.
r = Math.min(r, 16); int upperLimit = 1 << r;
int loopCount = b / r;
int j = 0;
int[] resultArray = new int[toSort.length];
int[] countingArray = new int[upperLimit];
while (j < loopCount) {
int rightShift = j * r;
radixSort(toSort, upperLimit, rightShift, resultArray,
countingArray);
Arrays.fill(countingArray, 0);
j++;
}
int mod = b % r;
if (mod != 0) {
upperLimit = 1 << mod;
int rightShift = r * loopCount;
countingArray = new int[upperLimit];
radixSort(toSort, upperLimit, rightShift, resultArray,
countingArray);
}
} private void radixSort(int[] toSort, int upperLimit, int rightShift,
int[] resultArray, int[] countingArray) {
int allOnes = upperLimit - 1;
for (int i = 0; i < toSort.length; i++) {
int radix = (toSort[i] >> rightShift) & allOnes;
countingArray[radix]++;
}
for (int i = 1; i < countingArray.length; i++) {
countingArray[i] += countingArray[i - 1];
} for (int i = toSort.length - 1; i >= 0; i--) {
int radix = (toSort[i] >> rightShift) & allOnes;
resultArray[countingArray[radix] - 1] = toSort[i];
countingArray[radix]--;
}
System.arraycopy(resultArray, 0, toSort, 0, resultArray.length);
} public static void main(String[] args) {
for (int j = 0, n = 2500; j < 5; j++, n = n * 10) {
System.out
.println("**************************************************");
System.out.println("Number to Sort is:" + n);
int upperLimit = Integer.MAX_VALUE;
int[] array = CommonUtils.getRandomIntArray(n, upperLimit);
System.out.print("Array to sort is:");
CommonUtils.printIntArray(array); int[] array1 = Arrays.copyOf(array, n);
new RadixSort().sortAndprint(array1); int[] array2 = Arrays.copyOf(array, n);
new RandomizedQuickSort().sortAndprint(array2);
}
}
}
RadixSort.java
排序算法七:基数排序(Radix sort)的更多相关文章
- 经典排序算法 - 基数排序Radix sort
经典排序算法 - 基数排序Radix sort 原理类似桶排序,这里总是须要10个桶,多次使用 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,临时忽视十位数 比如 待排序数组[ ...
- java排序算法之冒泡排序(Bubble Sort)
java排序算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数 ...
- 桶排序/基数排序(Radix Sort)
说基数排序之前,我们先说桶排序: 基本思想:是将阵列分到有限数量的桶子里.每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序).桶排序是鸽巢排序的一种归纳结果.当要被排序 ...
- 基础排序算法之快速排序(Quick Sort)
快速排序(Quick Sort)同样是使用了分治法的思想,相比于其他的排序方法,它所用到的空间更少,因为其可以实现原地排序.同时如果随机选取中心枢(pivot),它也是一个随机算法.最重要的是,快速排 ...
- js 实现排序算法 -- 冒泡排序(Bubble Sort)
原文: 十大经典排序算法(动图演示) 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来.走访数列的工作 ...
- 基数排序(radix sort)
#include<iostream> #include<ctime> #include <stdio.h> #include<cstring> #inc ...
- js 实现排序算法 -- 快速排序(Quick Sort)
原文: 十大经典排序算法(动图演示) 快速排序 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整 ...
- js 实现排序算法 -- 归并排序(Merge Sort)
原文: 十大经典排序算法(动图演示) 归并排序 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得 ...
- js 实现排序算法 -- 插入排序(Insertion Sort)
原文: 十大经典排序算法(动图演示) 插入排序 插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描, ...
随机推荐
- Tengine 补充
Tengine 补充 开机启动 chkconfig --list chkconfig --add nginx chkconfig nginx on 时间问题 service ntpd status 虚 ...
- 02python程序设计基础——字符串
字符串方法 format 1.替换字段名 在最简单的情况下,只需向 format 提供要设置其格式的未命名参数,并在格式字符串中使用未命名字段.此时,将按顺序将字段和参数配对.你还可给参数指定名称,这 ...
- Linux之bash的变量
1. 变量的显示,echo echo $变量 或 echo ${变量} eg. echo $HOME 或 echo ${HOME} 2. 变量的设置 变量的设置规则: (1)变量与变 ...
- 2019 计蒜之道 复赛 B. 个性化评测系统 (模拟,实现,暴搜)
24.02% 1000ms 262144K "因材施教"的教育方式自古有之,互联网时代,要实现真正意义上的个性化教育,离不开大数据技术的扶持.VIPKID 英语 2020 多万学员 ...
- vue2.0 之 过渡动画transtion
过渡的类名: 在进入/离开的过渡中,会有 6 个 class 切换 (v 是前缀,name = v) v-enter:定义进入过渡的开始状态.在元素被插入时生效,在下一个帧移除. v-enter-ac ...
- 【GDOI2014模拟】服务器
前言 直到比赛最后几分钟,才发现60%数据居然是一个水dp,结果没打完. 题目 我们需要将一个文件复制到n个服务器上,这些服务器的编号为S1, S2, -, Sn. 首先,我们可以选择一些服务器,直接 ...
- delphi 10.3 控件遮挡 webbrowser
听闻10.3的新特性之一,webbrowser可以被其他控件遮挡, 在等待10.3.1出来后才开始来尝鲜, 但在webbrowser上添加控件后, 发现控件还是被挡住了, 研究发现需要将控件的cont ...
- WWW基本概念
1.Internet 2.Intranet 3.万维网 注:万维网不等同于因特网,它只是因特网的一项服务. 4.TCP/IP 5.HTTP 注:HTTP是运行在应用层的一项服务. 注:服务器在没有用户 ...
- 【bzoj3277&&3474】串
*题目描述: 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). *输入: 第一行两个整数n,k.接下来n行 ...
- Java基础之方法详解
方法的所属性 在Java的语言中,方法相当于C语言中的函数,但是它与传统的函数也有着明确的不同:在结构化的语言中,函数是一等公民,整个程序是由一个个函数组成的:但是在面向对象的语言里,类是一等公民,整 ...