定义
与其他常规排序方式不同,基数排序不是根据元素的大小进行调换位置,进而形成有序列表,或者更严格来讲,基数排序不是直接根据元素整体的大小进行元素比较,而是将原始列表元素分成多个部分,对每一部分按一定的规则进行排序,进而形成最终的有序列表。
示例:扑克牌排序
排序方式:可以先按照牌的种类排序,例如红桃都在梅花前面,如排序规则为:"红桃"<"方块"<"梅花"<"黑桃",则排序后的结果为四个不同类型的牌堆,再按照牌的数值大小排序,则可以保证在排序之后:相同数值的牌,"红桃"在前,"黑桃"在后,不同数值大小的牌,则按照大小排序。
以两种颜色进行简单演示
由此可得知:基数排序的目的就是在按照上一套排序规则之后,形成的"已排序"列表中,按照新的规则,在"已排序"基础上再次进行排序。
与其他的排序方式比较可知:快排、堆排、希尔排序等,这些排序更偏重于利用数据结构特性减少时间复杂度和空间复杂度,基数排序则更偏重于提供多种排序规则,对复杂对象可以满足在不同的部分,按照不同的规则进行排序(或者说可以标志对象的某一部分在列表中的优先级)。
示例
以基数排序常用形式作为示例,即对一个整数数组进行排序,此处排序方式为:先按照元素个位上数字进行排序,再按照十位数字、百位数字。。。,最终形成的即为有序数组(负数需要分成另一部分操作,此处不考虑)。
演示数组:53,28,31,9,33,191,图示如下:
参考代码
public class t{
public static void main(String[] args){
int[] arr=new int[]{11,9,23,98,143,78,20,26,23,7,19,0,65,33};
Base.sort(arr);
for(int i:arr){
System.out.print(i+" ");
}
System.out.println();
}
}
class Base{
public static void sort(int[] arr){
boolean flag=true;//判断结束标志,待检查位数超过最高位结束
int index=0;//设定待检查位数
node[] base=new node[10];
while(flag){
flag=false;
flag=check(base,arr,index);
index++;
}
}
/*
完成数组arr与,数组链表base,两者之间的转换
addElement: arr->base
getElement: base->arr
*/
private static boolean check(node[] base,int[] arr,int index){
boolean flag=false;
int pos=0;//待存储的位置,也就是index位上的数字
int count=0;//表示arr数组待存储元素的位置
for(int i=0;i<arr.length;i++){
pos=(int)(arr[i]/Math.pow(10,index))%10;//获得index位上的数字
if(!flag&&pos!=0){//当数组中pos位全部为0,停止
flag=true;
}
addElement(base,pos,arr[i]);//把整个值添加到数组链表结构中
}
//show(base);//观察中间过程
for(int i=0;i<base.length;i++){
count=getElement(base,i,arr,count);//把数组链表结构中数据转移会arr数组
}
return flag;
}
/*
把value值,即数组上的值,存储到对应的数组链表结构的pos位置
*/
private static void addElement(node[] base,int pos,int value){
node tem=base[pos];
if(tem==null){
tem=new node(value);
base[pos]=tem;
}else{
while(tem.next!=null){
tem=tem.next;
}
tem.next=new node(value);
}
}
/*
把数组链表结构pos位置的值,存储到数组中
*/
private static int getElement(node[] base,int pos,int[] arr,int count){
node tem=base[pos];
while(tem!=null){
arr[count]=tem.value;
tem=tem.next;
count++;
}
base[pos]=null;//置空
return count;
}
//观察中间转换过程
private static void show(node[] base){
node tem=null;
for(int i=0;i<base.length;i++){
tem=base[i];
while(tem!=null){
System.out.print(i+": "+tem.value+" ");
tem=tem.next;
}
System.out.println();
}
}
}
class node{//便宜行事,属性公有访问
public int value;
public node next=null;
public node(int value){
this.value=value;
}
}
总结
按照不同位上数字的方式进行基数排序,对于相同大小的元素,不需要改变相对位置,即稳定排序。对每一位上排序,将数组arr转换到数组链表结构base上为O(n),将数组链表结构base再转换到数组arr上为O(r),最大数据为d位,总复杂度为O(d*(n+r))。
结合上述函数解释,即对个数上数字或者百位上数字都一样,即使为0,也需要将arr上该元素存储到base结构中,即每一个元素都要调用addElement函数,所以为O(n);将base结构上不为空的链表上数据转移回数组arr上,即每一个不为空的链表都要调用getElement函数,所以为O(r)。整个数组的最大元素为d位,则复杂度为O(d*(n+r))。