最近突然想到这么一个问题:
假如有<10亿的数据,每个数据不重复,同时是无序,不连续的,如何使用最小的空间来存储来这么多数据,同时又能快速的确认哪个数据有没有。
- 直接存储10亿个数据
一个int的类型,可以最大可以表示:2147483647,这个数大于10亿,所以可以使用一个int(4个字节)来表示一个数。
在这种情况下,需要的空间是4*10^9,大约需要4G的空间。
如果想去查找一个数据在或不在,此时需要把这么多的数据加载到内存中,分别遍历,需要O(n)的时间复杂度。
- 利用数组的index来存储
数组有一个优势就是可以根据index直接找到数据,正常情况下都是利用数组的空间来存储数据,现在是不是可以反过来利用index来表示数据。
数组的index默认从0增长到n,这个问题中说明了每个数据不重复,这个很符合index的特征,index是不可能重复的。
虽然说这组数据是无序和不连续的,可以将数组初始化成全零,对应存在的index将数据置1,
C/C++中可以构成数组最小的类型是char,那就可以new char[1024*1024*1024]的数组,如果对应index的数据纯在a[n]=1.
在这种情况下,需要的空间是10^9,大约是1G的空间
这个时候如果想查看一个数据在不在,只需要O(1)的时间复杂度。
- 基于数组的index的位存储
上面的方案已经将空间压缩1/4,是不是还有更优的方案呢?
其实只需要表示一个数字在或不在,那只要0和1就够。
这个时候数组的大小只需要10^9/8就够了,大约130MB,这么大直接加载到内存中也没有问题。
在这种情况下如何访问呢
假设想查看1000这个数在不在,可以通过以下方式:
index = 1000 / 8 = 125
pos = 1000 % 8 = 0
也就是说a[125]的0位表示的是1000。
通过a[index]&(0x01<<pos)来判断数据是不是存在
通过a[index] |= (0x01<<pos)来进行赋值
通过对比发现,通过位运算能够最大程度的减小存储空间,通过也能做到快速访问。