利用JAVA的BitSet实现数组排序

各种经典排序算法网上还是比较多的,但是此处实现一个时间复杂度为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下此类的分析或者直接看源码实现。

时间: 2024-11-04 16:27:30

利用JAVA的BitSet实现数组排序的相关文章

利用java开发一个双击执行的小程序

之前我们利用java写了很多东西,但是好像都没有什么实际意义. 因为有意义桌面小程序怎么都得有个界面,可是界面又不太好搞.或者 了解到这一层的人就少之又少了. 呀,是不是还得开辟一些版面来介绍awt和 swing... 算了 先把这个 双击执行的小程序 贡献出来. 这次 在分享一下源代码[以前还没有上传过源代码,布置怎么个搞法] 要求是: 输入一个 后缀名,然后输入所在目录,然后 点击查找,比如我们可以 输入F:\,然后查找 F盘下面的所有后缀名为比如.pdf 举例: 主要是 看了很多 资源,然

利用java日期类生成数据仓库维度表

利用java日期类生成数据仓库维度表 Date类: 最基础的日期时间类,返回一个相对日期的毫秒数.精确到毫秒,但不支持日期的国际化和分时区显示.Date 类从Java 开发包(JDK)1.0 就开始进化,当时它只包含了几个取得或者设置一个日期数据的各个部分的方法, 比如说月, 日, 和年. 这些方法现在遭到了批评并且已经被转移到了Calendar类里去了,这种改进旨在更好的处理日期数据的国际化格式. Calender类: 相对于Date更加强大的时间类,是抽象类,提供了常规的日期修改功能和国际化

利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)

最近看老罗的视频,跟着完成了利用Java操作MySql数据库的一个框架类JdbcUtils.java,完成对数据库的增删改查.其中查询这块,包括普通的查询和利用反射完成的查询,主要包括以下几个函数接口: 1.public Connection getConnection()   获得数据库的连接 2.public boolean updateByPreparedStatement(String sql, List<Object>params)throws SQLException  更新数据库

利用Java反射实现JavaBean对象相同属性复制并初始化目标对象为空的属性的BeanUtils

有时遇到将数据传输对象转换成JSON串会将属性值为空的属性去掉,利用Java反射实现JavaBean对象数据传输对象的相同属性复制并初始化数据传输对象属性为空的属性,然后转换成JSON串 package com.banksteel.util; import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Arrays;import java.ut

利用Java提供的Observer接口和Observable类实现观察者模式

对于观察者模式,其实Java已经为我们提供了已有的接口和类.对于订阅者(Subscribe,观察者)Java为我们提供了一个接口,JDK源码如下: 1 package java.util; 2 3 public interface Observer { 4 void update(Observable o, Object arg); 5 } 和我们上一篇实现的观察者一样,仅提供一个update方法用于接收通知者的通知做出相应改变. 我们再来看看Java为我们提供了一个怎样的通知者(Publish

学习MongoDB--(11):应用举例(利用java操作MongoDB)

原文地址:http://blog.csdn.net/drifterj/article/details/7948090 目录地址:http://blog.csdn.net/DrifterJ/article/category/1191327/2 前面我们都是通过shell来操作存取MongoDB的数据,shell中使用的语言就是javascript.我们这次说一下如何通过Java来访问操作MongoDB数据库的. Java驱动程序是MongoDB最早的驱动,已用于生产环境很长时间,十分稳定.可以到M

利用java.io.File类实现遍历本地磁盘上指定盘符或文件夹的所有的文件

2016-11-18 这是本人的第一篇随笔博客,纠结了半天还是选择自己学的时候比较用心的一些知识点上.利用java.io.File类指定本地的文件夹进行遍历所有的文件. package org.lxm.filedemo; import java.io.File; import java.util.Scanner; /* * 本程序是将某个盘的所有文件夹及其文件全部调出来的操作 */ public class FileAllDemo { public static void main(String

利用java 反射机制来实现一个servlet处理多种请求

如果我们想在一个servlet中处理多种请求(比如新闻的添加.删除),简单的可以在jsp提交表单的action路径中添加一个键值对,然后再servlet中接收后根据不同的值来调用不同的方法. jsp端 1 <form action="newsServlet?method=add" method="post"> 2 <input type="text" ..> 3 <input type="submit&qu

Java网络编程:利用Java mail包发送电子邮件

下面代码是利用Java mail包封装了一个发送邮件的类 import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.Me