• 位示图算法实现大数据的存储


              今天在看排序算法的时候,看到了用位示图法实现的,上面说可以大大减少内存的使用,尤其针对大数据的存储,数据量非常大的的时候,他的优点就比较明显了,因为他存储数据值依靠1个位来表示。具体是怎么回事呢,继续往下看。位图法,位图法,当然和位相关,下面我给出一组数组int[]{1, 3, 5,8},也许在普通的我们的编程中,我们肯定是存放在一个32位整形的数组中,1个32位整数,4个字节,4个数字总共16个字节,而如果用位图法,表示,可以用一个这么一个位字符串表示:

    10101001

    1出现的位置就是代表数字的值,第1,3,5,8个位置的值为1,就代表了这些数字的存在,这样一算只需要8位,也就是1个字节,比刚刚那个整整省了15个字节。可见这个算法的效率十分之高,但是又一个难题摆在面前了,如何存储和读取这样的形式中的数值无疑将是这个算法的最难点。

            首先是数据的存入过程,将整形数字存入相应的位,并把相应的位置的数字标记为1,就代表完成任务了,第一步,我们当然得先声明一个用来存放数值的数组:

    //声明了整形数组,最大的存放的数字的值可以到3 * 32
    	private static int[] bitmap = new int[3];
    我在这里定义了3个单位的数组,每个数组值含32位,也就是说,是3个32位0排成一起,那最大表示的值就是96了。这个很好理解吧。为了容易懂,把操作改小了容易懂。接下来就是我们要传入值进行位设置操作了,主要分为以下步骤:

    1.算出是在哪个一个数组下标的范围内,除以32去商

    2.知道了哪个下标了,算出在此下标的偏移位置,再取余32操作

    3.根据偏移量,折算出此时的二进制形式值,就是一直左移到那个位置上

    4.最后进行或运算,把那个位置的值变为1,操作结束

    附上代码:

    /**
    	 * 传入的数字,用来存储在位图中
    	 * @param number
    	 */
    	public static void setBitmapNumber(int number){
    		int index = number / 32;
    		int pos = number % 32;
    		int flag = 1;
    		
    		//如果刚好整除
    		if(pos == 0){
    			//算上个整数位的
    			pos = 32;
    			index--;
    		}
    		
    		for(int j=0; j<pos-1; j++){
    			//左移pos个位置,用于后面的位运算
    			flag = flag << 1;
    		}
    		
    		//找到此数组的位置,进行或运算,把此位置的0变为1
    		bitmap[index] = bitmap[index] | flag; 
    		System.out.println(MessageFormat.format("第{0}下标,第{1}位,值为{2}", index, pos, bitmap[index]));
    	}
    我在这里的测试例子的输出结果,输入的数字为:

    int[] initArray = new int[]{15, 31, 75};
    		for (int i = 0; i < initArray.length; i++) {
    			setBitmapNumber(initArray[i]);
    		}
    输出为:

    第0下标,第15位,值为16,384
    第0下标,第31位,值为1,073,758,208
    第2下标,第11位,值为1,024
    第0下标的意思是这个1的位置在bitmap[0]中,

    75因为已经过了2给32,所以在bitmap[2]中,第11位置,十进制的值就为2的10次方,就是1024了。

    0000000000000010000000000000001
    0000000000000000000000000000000
    0000000000100000000000000000000
    上面就是此操作的存储结果。
    /**
    	 * 整数表示成二进制位的形式
    	 * @param number
    	 */
    	public static void setIntToBit(int number){
    		int flag = 1;
    		for(int j=0; j<31; j++){
    			if((number & flag) == 1){
    				//说明最右边一位为1
    				System.out.print(1);
    			}else{
    				System.out.print(0);
    			}
    			number = number >> 1;
    		}
    		
    		System.out.print("
    ");
    	}
    我写了这个方法,转化了一下。就是不断右移,输出,循环操作。
          当然了,有存入必然有取出的过程,思路主要如下:

    1.遍历biamap[]整形数组,从0下标到最后一个小标

    2.在每个下标中,再执行32位的逐位扫描,判断有无设置1的存在

    3.如果有1的存在,此时的偏移量+下标*32,就是之前下标的总位数,就是最终的值了

    代码如下:

    /**
    	 * 获取位图中所存放的数字
    	 */
    	private static void getBitmapNumber(){
    		int temp = 0;
    		//在单个数字中的位偏移量
    		int offset = 1;
    		int flag = 1;
    		
    		for(int i=0; i<bitmap.length; i++){
    			temp = bitmap[i];
    			
    			for(int j=0; j<31; j++){
    				if((temp & flag) == 1){
    					//说明最右边一位为1
    					System.out.println(MessageFormat.format("第{0}下标,第{1}位,值为{2}", i, offset, 32 * i + offset));
    				}
    				
    				temp = temp >> 1;
    				offset++;
    			}
    			//重置偏移量为1
    			offset = 1;
    		}
    	}
    测试代码输出的结果:

    第0下标,第15位,值为15
    第0下标,第31位,值为31
    第2下标,第11位,值为75
    里面涉及了比较多的位运算,大家可以自己先运行一下,他到底是怎么算的。看起来操作都已经成功了嘛,但是,我在调试程序的时候发现了一个问题,每当我用32的整数倍的值去算的时候,就会失败,首先存入就会失败,没错,就是越界的问题,后来想了想总共32位,在java里没有无符号整形的说法,所以肯定有1位要作为符号位,所以只能表示到31的位置,32位就会出错,不信的话,可以把我的代码拷贝运行,看一下结果。我这个只是一个小小Demo类型的测试,当数据量非常大的时候,你可以用几个M的字节,去存放海量的数据,肯定比每个传统存储形式要高效很多,而且位运算的执行效率比普通的加减乘除也来的直接。再一次见证了算法的魅力了吧。最后贴出完整程序供大家学习:

    package BitmapStore;
    
    import java.text.MessageFormat;
    
    /**
     * 位示图法存储数据,面对大数据的时候可以减少内存的使用
     * @author lyq
     *
     */
    public class Client {
    	//声明了整形数组,最大的存放的数字的值可以到3 * 32
    	private static int[] bitmap = new int[3];
    	 
    	public static void main(String[] agrs){
    	//	int[] initArray = new int[]{2, 15, 33, 75, 178, 1000};
    		int[] initArray = new int[]{15, 31, 75};
    		for (int i = 0; i < initArray.length; i++) {
    			setBitmapNumber(initArray[i]);
    		}
    		
    		for (int i = 0; i < initArray.length; i++) {
    			setIntToBit(bitmap[i]);
    		} 
    		
    		getBitmapNumber();
    	}
    	
    	/**
    	 * 传入的数字,用来存储在位图中
    	 * @param number
    	 */
    	public static void setBitmapNumber(int number){
    		int index = number / 32;
    		int pos = number % 32;
    		int flag = 1;
    		
    		//如果刚好整除
    		if(pos == 0){
    			//算上个整数位的
    			pos = 32;
    			index--;
    		}
    		
    		for(int j=0; j<pos-1; j++){
    			//左移pos个位置,用于后面的位运算
    			flag = flag << 1;
    		}
    		
    		//找到此数组的位置,进行或运算,把此位置的0变为1
    		bitmap[index] = bitmap[index] | flag; 
    		System.out.println(MessageFormat.format("第{0}下标,第{1}位,值为{2}", index, pos, bitmap[index]));
    	}
    	
    	/**
    	 * 获取位图中所存放的数字
    	 */
    	private static void getBitmapNumber(){
    		int temp = 0;
    		//在单个数字中的位偏移量
    		int offset = 1;
    		int flag = 1;
    		
    		for(int i=0; i<bitmap.length; i++){
    			temp = bitmap[i];
    			
    			for(int j=0; j<31; j++){
    				if((temp & flag) == 1){
    					//说明最右边一位为1
    					System.out.println(MessageFormat.format("第{0}下标,第{1}位,值为{2}", i, offset, 32 * i + offset));
    				}
    				
    				temp = temp >> 1;
    				offset++;
    			}
    			//重置偏移量为1
    			offset = 1;
    		}
    	}
    	
    	/**
    	 * 整数表示成二进制位的形式
    	 * @param number
    	 */
    	public static void setIntToBit(int number){
    		int flag = 1;
    		for(int j=0; j<31; j++){
    			if((number & flag) == 1){
    				//说明最右边一位为1
    				System.out.print(1);
    			}else{
    				System.out.print(0);
    			}
    			number = number >> 1;
    		}
    		
    		System.out.print("
    ");
    	}
    	
    }
    


  • 相关阅读:
    归并排序(Merge Sort)
    AtCoder AGC035D Add and Remove (状压DP)
    AtCoder AGC034D Manhattan Max Matching (费用流)
    AtCoder AGC033F Adding Edges (图论)
    AtCoder AGC031F Walk on Graph (图论、数论)
    AtCoder AGC031E Snuke the Phantom Thief (费用流)
    AtCoder AGC029F Construction of a Tree (二分图匹配)
    AtCoder AGC029E Wandering TKHS
    AtCoder AGC039F Min Product Sum (容斥原理、组合计数、DP)
    AtCoder AGC035E Develop (DP、图论、计数)
  • 原文地址:https://www.cnblogs.com/bianqi/p/12184155.html
Copyright © 2020-2023  润新知