【算法-位图法】在海量数据中查找重复元素

什么是位图法?

举个简单例子,在java中一个int类型的数有32位,而这32只表示一个数太过浪费,于是就考虑让这32位可以表示32个数,每一位表示该数是否存在,例如:

这里用16位的二进制就能表示十六个数字,1表示存在,0表示不存在,上图就表示存在(16,12,6,4,1)这五个数。

在海量数据中查找重复出现的元素或者去除重复出现的元素也是常考的问题。针对此类问题,一般可以通过位图法实现,例如,已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

本题最好的解决办法就是通过位图法来实现。

解题思路:

8位整数可以表示的最大十进制数值为99999999,如果每个数字对应于位图中的一个bit位,那么存储八位整数需要99999999bit大约99Mbit,因为1Byte=8bit,所以99Mbit折合成内存为99/8=12.375MB的内存,及可以只用12.375MB的内存表示所有的8位数电话号码的内容。

程序代码如下:

import java.util.Random;
public class DuplicateTelephone{
	int randNum=100;
	int min=10000000;
	int max=99999999;
	int len=(max-min+1);
	int bit_per_word=32;
	
	int  word_offset(int b){
		return b/bit_per_word;
	}
	int bit_offset(int b){
		return b%bit_per_word;
	}
	void setBit(int[] words,int n){
		int temp=n;
		temp-=min;
		words[word_offset(temp)]|=(1<<bit_offset(temp));
	}
	void clearBit(int[] words,int n){
		words[word_offset(n)]&=~(1<<bit_offset(n));
	}
	boolean getBit(int[] words,int n){
		int result=words[word_offset(n)]&(1<<bit_offset(n));
		return result!=0;
	}
	public void sort(){
		int arr[]=new int[randNum];
		System.out.println("数组大小:"+randNum);
		int[] words=new int[len/bit_per_word+1];
		int count=0;
		Random r=new Random();
		for(int j=0;j<randNum;j++){
			arr[j]=r.nextInt(len);
			arr[j]+=min;
			System.out.print(arr[j]+" ");
		}
		System.out.println();
		for(int j=0;j<randNum;j++){
			setBit(words,arr[j]);
		}
		System.out.println("排序后a为:");
		for(int i=0;i<len;i++){
			if(getBit(words,i)){
				System.out.print(i+min+" ");
				count++;
			}
		}
		System.out.println();
		System.out.println("总个数为:"+count);
		
	}
	public static void main(String[] args){
		new DuplicateTelephone().sort();
	}
	
}

运行的结果为:

数组大小:100
46875852 63059260 46888254 54260213 84901496 58876931 28753082 72176161 30014077 84850078 31950213 14204495 26230245 27850510 32455193 68366470 52371514 87138574 94489525 45678876 90450237 42341450 24655913 43282877 49446847 42320941 84516417 35313419 59903775 35761368 11337291 46450272 93115232 55490862 11998766 73065445 47942924 18581547 58818184 77268172 99380374 80558928 16202169 95248485 20644397 34063612 20913170 94324174 67502076 80090509 45820098 81312556 32858162 16476350 15080157 45289864 99027018 87240729 89981567 52198533 39085177 76494986 65134775 93827194 13834939 71752586 32473580 67759555 29073921 72452538 98008564 58115033 64844962 59371680 86529508 69079674 61521841 96326355 25073903 19962950 33966761 83534685 38855968 14084970 85023410 78286139 81124660 48083315 57208466 72108161 26193937 67771844 22611251 51376666 43171943 82768547 47796300 19563949 91347170 47639405
排序后a为:
11337291 11998766 13834939 14084970 14204495 15080157 16202169 16476350 18581547 19563949 19962950 20644397 20913170 22611251 24655913 25073903 26193937 26230245 27850510 28753082 29073921 30014077 31950213 32455193 32473580 32858162 33966761 34063612 35313419 35761368 38855968 39085177 42320941 42341450 43171943 43282877 45289864 45678876 45820098 46450272 46875852 46888254 47639405 47796300 47942924 48083315 49446847 51376666 52198533 52371514 54260213 55490862 57208466 58115033 58818184 58876931 59371680 59903775 61521841 63059260 64844962 65134775 67502076 67759555 67771844 68366470 69079674 71752586 72108161 72176161 72452538 73065445 76494986 77268172 78286139 80090509 80558928 81124660 81312556 82768547 83534685 84516417 84850078 84901496 85023410 86529508 87138574 87240729 89981567 90450237 91347170 93115232 93827194 94324174 94489525 95248485 96326355 98008564 99027018 99380374
总个数为:100

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值