数据存储与位映射

我们秋天的时候收获了好多的麦子,我们需要在收割以后将麦子存储到仓库中,这样麦子才不会被偷走,也不会因为被雨淋湿等原因让我们损失掉这些麦子。麦子就像是我们计算机中的数据,我们需要把有用的数据保存起来,当我们需要的时候就在仓库中拿出来。我们的仓库的大小是固定的,那么我们怎么来有效果的进行存取是个问题。

那么我们使用的计算机是如何存取数据的呢?还是以仓库存储麦子为例,假设,想要知道都哪些户吧麦子存在仓库中了,我们首先要给每户人家编号,编号都是大于0的整数。然后我们将以计算机内存的形式来记录这哪些人家在仓库中存了粮食。我们用一个乒乓球来模拟二进制的0,1.乒乓球黑色表示1,乒乓球白色表示0.如果那么有8个小球的话,这八个小球有2222222*2=256种不同的排列组合。所以就可以表示的用户的编号是0-255.如果有10w个用户需要表示。那么每个编号只用8个小球用不同的组合方式去表示不同编号是远远不够的,我们就要增加小球的数量去表示一个用户的编码。我们如果用64个小球去表示一个用户的编码呢?不管你是编号1,还是编号23231都可以用64个小球的某一种排列组合去表示。这样看,每个小球都是会占用空间的,而且每一组都放在一起,如果要记录的用户很多的话我们要需要多少空间去存放这些小球呢?可能最后因为存放这些小球的空间比存储粮食的粮仓都大。这样的空间开销是恐怖的。计算机的存储原理就是这样的,我们规定要用多少个内存空间去表示一个数字,我们例子中的一个小球就表示一个的单位的内存单元。一个内存单元有两种情况0或者1,内存单元都是连续排列的,这样我们就规定可以用一定连续个数的内存单位,通过连续内存空间中每个单元取1或0的排列组合来表示一个数字了,这就是使用二进制去存储数据。我们知道1在二进制空间的表示为1.而255的二进制表示为11111111.所以用64个连续的空间去表示1实在是有点浪费内存资源了,这样的数只需要一位就可以表示1这个编号.我们将每个存储单元的单位用bit表示。

当我们想要加入一个数的时候,我们因为内存空间是连续的。我们可以插入到这组空间的后面,但这样的导致,里面存储的数字大小并没有规律。可能会存储成这样的情况[1,64,32,2],这组数据就是无序的,这样我们想查找某一个数字的时候就需要遍历一遍所有的存储空间。同样对于现在动辄以亿为单位的用户的存储来说,如果我们要对1亿个用户进行存储,所需要的内存空间是1000000000*64个单元。对于大数据的存储,这样的空间消耗是很巨大的,同时这样的存储如果将他变成有序的存储,我们还需要大量的运算时间去将他排序。以用64个bit来表示一个数字为例,如果我们想要维护一个数据的有序性,将一个数插入这个数据的时候, 我们需要找到这个数据应该插入的位置,这就需要遍历这个数据,在找到这个位置后,因为数据是连续的,要从后向前的将后面的数据依次向后挪动64个bit的位置,来空出空间给插入的数据。

在现在超大规模的数据量下,对这组数据中哪些是重复的,并将重复的去掉。我们就需要一遍一遍的遍历这组数据。而如果要对大数据重新的排序,我们不仅仅要重新的遍历,还要重复多次的数据。这些操作在大数据的情况下,会耗费大量的计算时间。我们需要一种方便的快速方便的方法来对用户的增删查改等操作快速的响应,同时还能减小存储空间。当们需要记录一组大规模的数据,比如微信用户在线管理这种数据操作的时候。当用户上线的时候我们将用户ID加入进数组,退出的时候将用户删除出数组。当有用户登录的时候,系统需要检查是否是重复登录,这就相当于大数据去重的过程。这样的增删查改等操作就会带来大量的计算时间。而为了减少这种计算时间,我们将用户的ID全都按顺序存储在系统中,在给定一个标识,表示用户是否在线。这样可以同样的记录是否用户在线,而且增删查改的速度是O(1)。但是占用的内存空间又很大。我们的一个折中的方法就是位映射。用一个内存空位置的地址编号来表示一个数据的编号。这样我们就不用花大量的内存空间去存储内存的ID编号了。我们设置一个内存地址为起始点,这个地址我们将它编号当做0,我们可以通过计算得到内存地址的相对位置,这个相对位置就是这个数据ID编号。如果这个地址ID中的数字是1,那么表示该ID在线,如果是0就表示不在线。这种用地址编号来替代数字编号的方法就叫做位映射。
我们用JAVA为例实现这种位映射:
我们规定,查找一个数字是否是在这个数组中重复出现。
1.创建映射空间
我们使用JAVA中 byte 这种格式来创建存映射储空间。不管是什么数据格式都是可以的,在内存方面来看,不同格式间的区别是内存给它分配的内存空间上的差距。一个byte数据内存会给它分配8bit的空间。
一个byte可以表示8个数。用多个连续的byte数据就可以表示很多个数了。所以映射的代码如下:

public class chongfu {
	private byte[] arry = new byte[100];
	private int number ;
	private int place ;
	private int yushu;
	// number 是要映射的数字
	// place 表示要存储在第几个byte中
	// yushu 表示在这个byte中的位置
	

2.映射关系的构建
查找 number 这个数,在对应的映射位置的值如果为0,则说明这个数没存过,如果为1,则说明这个数被存储过。
byte数据格式在内存中是8bit的存储空间,但是它一个数字显示的是一个整数,所以我们需要将它还原成二进制的表示。

public boolean find() {
		int zf = 0;//0为正,1为负
		place = number / 8;
		yushu = number % 8;
		//找到 我们要找的 目标所在的byte 位置
		int remember = arry[place];	
		//对这个byte位置中的数据转换成2进制的字符串
		String C =Integer.toBinaryString(remember);
		//C 是 一个二进制的字符串
		//以二进制书写顺序的格式存储
		//1)这里的L 就是一个字符表示 一位,一共八个字符表示八位
		//2)L中的字符位置,与二进制中表示位置顺序一直,L[0]是最高位,向左依次递减,L[7]位数最低。
		//二进制中00000010 表示 2,L跟这种表示向符合。L[6] = '1';
		if(remember < 0) {
			zf = 1;
			remember = -remember;
		}

		char[] L= new char[]{'0','0','0','0','0','0','0','0'};
		int gap = 8 - C.length();		
		char[] newarry =C.toCharArray();
		for(int i = 0;i<C.length();i++) {
			L[gap + i]=newarry[i];
		}
		if(zf == 1) {
			L[0] = '1';
		}
		if(L[8-yushu - 1] == '1') {
			return true;
		}
		else {
			L[8-yushu - 1] = '1';			
			int m = Integer.parseInt(result,2);
			arry[place] = (byte)m;
			}	
		return false;
	}

跟据代码,如果我们需要查找的数重复则返回True。如果不重复,则返回值为False,并将查找的数加入到映射空间中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值