最近两周学习研究了有关大数据的解决办法,下面就M个int(数据量很大,大于内存)排重进行浅层分析。做这种大数据的问题,我们要真正的动脑筋去想解决办法,在可行的条件下最好自己去实践一下,否则也只能是纸上谈兵。
对几亿个int型数据进行排重,我们的电脑内存空间都是有限的【以1G内存为例,我们最多存2^30B,也就是是2^28个int(1GB=1024MB,1MB=1024KB,1KB=1024B)】想要把数据都装入数组中,那显然是装不下的~~那么怎么样才可行呢?
下面分析一下解决办法:
方法一:
将大数据分为若干部分,在每个小部分里面先进行一次排序(从大到小),每次从每个部分中取出各自最大的那个,再在其中选出最大存入文件,在拿若干个数据进行比较,选出第二大的,若与前一个元素相同,则舍去,不同则写入文件。这样依次进行下去,遍历完所有的数据也就完成了排重的工作。
但是这个方法需要扫描数据两遍,比较费事,在时间花销上应该是很大的。
那么有没有其他更好的方法呢?
方法二:
1个int—>4个Byte—>32个bit
试想想,我们可不可以在1个int里存入32个数据的相关信息呢?这样的话,是不是将占用的内存降低到1/32了呢?
将一个int表示为32位的01字符串,如果对应位置的数据存在就把bit设为1,不存在就为0。
假设有数据“5”,那么就把第5个位置的0改成1
将01串转换成int存入数组里就可以了
下面看一下我写的方法,比较简单
package Eliminate;
/**
* 一组int很多,排重
* @author Administrator
* 最多有2^32(2147483647])个int数字,用一个bit来表示,最多用2^27大小的数组来表示
*/
public class Eliminate {
/**
* 将一个32位的字符串转成一个整数
*
* @param s
* @return
*/
public int stringTOint(String s) {
int a=(int) (((int) s.charAt(0) - 48) * (2147483647+1));
int b=(int)((int) s.charAt(1) - 48) * 1073741824 + ((int) s.charAt(2) - 48)* 536870912
+ ((int) s.charAt(3) - 48) * 268435456+ ((int) s.charAt(4) - 48) * 134217728
+ ((int) s.charAt(5) - 48) * 67108864 + ((int) s.charAt(6) - 48) * 33554432
+ ((int) s.charAt(7) - 48) * 16777216 + ((int) s.charAt(8) - 48) * 8388608;
int c=(int)((int) s.charAt(9) - 48) * 4194304 + ((int) s.charAt(10) - 48)*2097152
+ ((int) s.charAt(11) - 48) * 1048576 + ((int) s.charAt(12) - 48)*524288
+ ((int) s.charAt(13) - 48) * 262144+ ((int) s.charAt(14) - 48) * 131072
+ ((int) s.charAt(15) - 48) * 65536 + ((int) s.charAt(16) - 48) * 32768
+ ((int) s.charAt(17) - 48)*16384+ ((int) s.charAt(18) - 48) * 8192
+ ((int) s.charAt(19) - 48)*4096 + ((int) s.charAt(20) - 48) * 2048
+ ((int) s.charAt(21) - 48) * 1024 + ((int) s.charAt(22) - 48) * 512
+ ((int) s.charAt(23) - 48) * 256 + ((int) s.charAt(24) - 48)* 128
+ ((int) s.charAt(25) - 48) * 64 + ((int) s.charAt(26) - 48)* 32
+ ((int) s.charAt(27) - 48) * 16+ ((int) s.charAt(28) - 48) * 8
+ ((int) s.charAt(29) - 48) * 4+ ((int) s.charAt(30) - 48) * 2
+ ((int) s.charAt(31) - 48);
return a+b+c;
}
/**
* 将int型转化为32位的bit
*/
public String intTOstring(int index){
String str=Integer.toBinaryString(index);
int strlength=str.length();
if(strlength<32){
for(int i=0;i<32-strlength;i++){
str="0"+str;
}
}
return str;
}
/**
* 打印最终排重结果输出
* @param args
*/
public void print(int src[]){
int number;
int count=0;
//将src数组中的数据还原成01字符串,找出相应位置的下标
//循环src数组
for(int i=1;i<src.length;i++){
String s=intTOstring(src[i]);
System.out.println(s);
for(int j=0;j<s.length();j++){
if(s.charAt(j)=='1'){
number=(i-1)*32+j;
count++;
System.out.print(number+" ");
}
}
System.out.println();
}
System.out.println("排重后的数据有"+count+"个");
}
}
测试代码:
package Eliminate;
import java.util.Random;
public class Test {
private static int SrcSize=80000;//最多用2^27大小的数组来表示
private static int M =1000000;//数据量
private static int [] src=new int [SrcSize];
private static Random r=new Random();
/**
* 主函数
* @param args
*/
public static void main(String args[]){
Long BeginTime=System.currentTimeMillis();
Eliminate e=new Eliminate();
int temp;//随机数
int number;//商
int index;//数组下标
int mod;//余数
int x;
for(int i=0;i<M;i++){
temp=r.nextInt(2000000);
System.out.print(temp+" ");
System.out.println();
number=temp/32;//取商
index=number+1;
mod=temp%32;//取余
//将int型转化为32位的bit
String str=e.intTOstring(src[index]);
//修改mod处的bit值
String newStr=new String();
for(int j=0;j<32;j++){
char c=str.charAt(j);
if(j==mod){
newStr=newStr+1;
}else{
newStr=newStr+c;
}
}
//将修改后的字符串转化为int,放回数组
x=e.stringTOint(newStr);
src[index]=x;
}
e.print(src);
Long EndTime=System.currentTimeMillis();
System.out.println("排重时间为:"+(EndTime-BeginTime));
}
}
由于时间问题,没有对很庞大的数据进行测试。这里的数据量为100万,数组大小为8万
测试结果:
排重后的数据有786678个
排重时间为:9344
个人认为排重速度还是不错的~~是不是很有效哟~~
下面进行了一个小数据的测试,证明方法的有效和正确性:
测试结果:
随机产生数据50个:
83 62 85 29 98 21 22 36 84 13 50 33 90 39 17 26 90 52 15 56 54 85 19 48 75 46 93 36 52 14 8 44 68 36 24 22 63 30 54 18 28 95 92 98 92 67 36 49 63 51
00000000100001110111011010101110
8 13 14 15 17 18 19 21 22 24 26 28 29 30
01001001000010101111101010000011
33 36 39 44 46 48 49 50 51 52 54 56 62 63
00011000000100000001110000101101
67 68 75 83 84 85 90 92 93 95
00100000000000000000000000000000
98
排重后的数据有39个
排重时间为:15
以上就是M个int(数据量很大,大于内存)排重的分析及解决方案,大数据问题还有很多很多,还需要进一步的分析研究~~应该会很有趣哟~~
分享到:
相关推荐
1.程序分析:利用for循环控制100-999个数,每个数分解出个位,十位,百位。 【程序4】 题目:将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。 程序分析:对n进行分解质因数,应先找到一个最小的质数k...
程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除, 则表明此数不是素数,反之是素数。 public class lianxi02 { public static void main(String[] args) { int count = 0; for(int i=...
10.4有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成前面m个数。 75 写一函数实现以上功能,在主函数中输入n个整数,并输出调整后的n个数。 75 10.5有一字符串,包含n个字符。写一个函数,将此字符串中从...
给定任意次序的车厢,通过转轨站将车厢编号按顺序重新排成1~n。转轨站共有k个缓冲轨,缓冲轨位于入轨和出轨之间。开始时,车厢从入轨进入缓冲轨,经过缓冲轨的重排后,按1~n的顺序进入出轨。缓冲轨按照先进先出方式...
約瑟夫問題可用代數分析來求解,將這個問題擴大好了,假設現在您與m個朋友不幸參與了這個遊戲,您要如何保護您與您的朋友?只要畫兩個圓圈就可以讓自己與朋友免於死亡遊戲,這兩個圓圈內圈是排列順序,而外圈是自殺...
⾸先我们 将int划分为2^16个区域,然后读取数据统计落到各个区域⾥的数的个数,之后我们根据统计结果就 可以判断中位数落到那个区域,同时知道这个区域中的第 ⼏⼤数刚好是中位数。然后第⼆次扫描我们只统计落在这个...
本题主要是要求设计一个程序,让用户输入正整数m ,它代表一个人民币钱数(元数),由程序计算一个最有方法,使人民币纸币的张数最少,并凑成上述的钱数m 。 ///////////////////////////////////////////// 程序...
4.4 我有个函数,它应该接受并初始化一个指针void f(int *ip) f static int dummy = 5; ip = &dummy;g 但是当我如下调用时: int *ip; f(ip); 调用者的指针却没有任何变化。. . . . . . . . . . . . . . . 18 4.5 我...
int类型,该类型占两个字节的内存空间,所以每个元素均占有两个 字节(图中每一格为一字节)。 二维数组元素的表示方法 二维数组的元素也称为双下标变量,其表示的形式为: 数组名[下标][下标] 其中下标应为整型...
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) { int i, j; Create PDF files without this message by purchasing novaPDF printer (http://www.novapdf.com) if ((start_addr & ...
题目:有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。 1. 程序分析:首先判断此数是否大于最后一个数,然后再考虑插入中间的数的情况,插入后 此元素之后的数,依次后移一个位置。 2....
四 系统实现与测试 4.1 主菜单 4.1.1主菜单流程图 图4.1主菜单流程图 4.1.2主菜单代码 int main() { int m; string p; int t=1; while(t!=0) { system("cls"); cout****************欢迎进入排班系统*
四 系统实现与测试 4.1 主菜单 4.1.1主菜单流程图 图4.1主菜单流程图 4.1.2主菜单代码 int main() { int m; string p; int t=1; while(t!=0) { system("cls"); cout****************欢迎进入排班系统**************...
/*最多200个商品*/ 2 系统设计 2.1 总体设计 按系统分析的功能要求将系统划分为以下几个主要功能模块: 文件管理 文件打开、关闭:对于刚输入或进行操作后的商品信息,在建立新的商品库存量后, 可以把其保存在一个...
在满二叉树中,每一层上的结点数都达到最大值,即在满二叉树的第k层上有2k-1个结点,且深度为m的满二叉树有2m-1个结点。 完全二叉树是指这样的二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只...
o m m u n i c a t i n go b j e c t)的重复模式。这些模式解决特定的设计问题,使面向对象设计更灵活、优雅,最终复用性更 好。它们帮助设计者将新的设计建立在以往工作的基础上,复用以往成功的设计方案。 一个...
"isqlw" 这是SQL2000的我也提供一下吧,这个可以起到SQL2000的查询分析器。 "devenv" 启动相应版本的VS Studio 17、Ctrl提示透明窗口 这是一个比较有意思的键。VS2005下,当你在调试代码的时候,有时候提示信息会...
P3 支持第二功能:RXD、TXD、INT0、INT1、T0、T1 单片机内部 I/O 部件:(所为学习单片机,实际上就是编程控制以下 I/O 部件,完成指定任务) 1. 四个 8 位通用 I/O 端口,对应引脚 P0、P1、P2 和 P3; 2. 两个 16 位...
角色是一组权限的集合,将角色赋给一个用户,这个用户就拥有了这个角色中的所有权限。 系统预定义角色 预定义角色是在数据库安装后,系统自动创建的一些常用的角色。下面我们就简单介绍些系统角色: CONNECT...
51 Int.Cl. E04D 5/10 11 公开号 CN123917A 21 申请号 98 112102.0 22 申请日 98. 6.17 71 申请人 重庆大学 72 发明人 江涛 李燕红 74 专利代理机构 重庆大学专利事务所 代理人 张敏 54 发明名称 屋面...