各种经典排序算法网上还是比较多的,但是此处实现一个时间复杂度为O(n)(不完全准确,有一定条件)的排序算法。借助JAVA的BitSet来实现,仅提供一个思路。

       废话不多说,直接上代码:

public static void sort(){
 int[] arr = new int[]{32,21,7,29,18,50};
 int max = max(arr);
 System.out.println(max);
 BitSet bitSet = new BitSet(max);
 //初始化bitSet
 for(int i=0;i<bitSet.length();i++){
       bitSet.set(i,false);
 }
 for(int j=0;j<arr.length;j++){
       bitSet.set(arr[j],true);
 }
 int i=0;
 for(int k=0;k<bitSet.length();k++){
     if(bitSet.get(k))
        arr[i++] = k;
 }
     System.out.print(Arrays.toString(arr));
}
 
private static int max(int[] arr){
  int max = 0;
  for(int item:arr){
     if(item>max){
        max = item;
     }
  }
  return max;
}

  借助BitSet位存储来对应到具体的某一个排序的值,当然借助别的形式也可以实现,比如new int[] 数组,其长度同样为待排序数组的最大值,但是这样是有限制的,int的最大值是Integer.MAX_VALUE(2147483647),最小值是Integer.MIN_VALUE(-2147483648)。一般情况下是够用。关键是占用空间问题,一个int是4个字节,32位,所以如果指定int的长度,则会需要更大的存储空间。假设指定int长度为5,则存储需要20个字节(相当于640位)。而BitSet指定长度后,是按照位进行数据存储,这样数据就会少很多。所以BitSet常用于存储海量数据。

      BitSet可以存储海量数据,但是同时,BitSet会过滤重复的内容,因为它是以true/false来标志的,所以要是对于重复的内容就不能直接使用了,如果非要可能具有相同内容进行排序,可以用以下的方式来实现。

     思路:存储某个值出现几次,需要一个存储KV的数据结构。这里使用concurrentHashMap来实现。后面会说明原因。废话不多说,依旧直接上代码

public static void sort(){
   int[] arr = new int[]{2,1,7,6,2,3,5,2,6};
   Map<Integer,Integer> count = new ConcurrentHashMap<Integer,Integer>(arr.length);    #增加一个Map对象存储
    int max = max(arr);
   System.out.println(max);
   BitSet bitSet = new BitSet(max);
   //初始化bitSet,默认为false,可以不设置
   for(int i=0;i<bitSet.length();i++){
        bitSet.set(i,false);
   }
   for(int j=0;j<arr.length;j++){
        bitSet.set(arr[j],true);

        if (count.containsKey(arr[j])){
            count.put(arr[j],count.get(arr[j])+1);
       }else{
            count.put(arr[j],1);
       }
  }
   Set<Map.Entry<Integer,Integer>> sets = count.entrySet(); 
   for(Map.Entry<Integer,Integer> entry:sets){
     if(entry.getValue() == 1){
      count.remove(entry.getKey());    #遍历Map,将只出现一次的删除掉
     }
   }  
  int i=0;
   for(int k=0;k<bitSet.length();k++){
     if(bitSet.get(k)){
         if(!sets.isEmpty()){
             if (count.containsKey(k)){    #若Map集合包含有出现1次以上的数值,则按出现的次数进行操作
                int cc = count.get(k);
                 for(int j=0;j<cc;j++){
                    arr[i++] = k;
                 }
                count.remove(k);    #将已经处理过的移除
             }else{
                   arr[i++] = k;
             }
         }else{
            arr[i++] = k;
         }
     }
   }
 System.out.println(Arrays.toString(arr));
}

private static int max(int[] arr){
 int max = 0;
 for(int item:arr){
   if(item>max){
     max = item;
   }
 }
 return max;
}

  可以看到在代码23行和35行执行了map的remove操作,而且在操作之后进行又进行了读操作。由于HashMap是非线程安全的,在进行读写操作执行时,会发生异常,尤其在编码中,如果在线上项目,除非你能确定使用场景,否则一但HashMap操作不当,就会造成各种异常情况,而且可能还不太好排查。而ConcurrentHashMap是线程安全的,而且其内部的加锁机制也不是以前粗暴的加锁方式,也更优雅。有兴趣的同学可以Google下此类的分析或者直接看源码实现。