哈希----位图

位图

位图概念

1. 面试题
40 亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这 40 亿个数中。【腾讯】
1. 遍历,时间复杂度 O(N)
2. 排序 (O(NlogN)) ,利用二分查找 : logN
3. 位图解决
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比
特位来代表数据是否存在的信息,如果二进制比特位为 1 ,代表存在,为 0 代表不存在。比如:

 

2. 位图概念
所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。
#pragma once
#include<iostream>
#include<vector>
namespace MySTL
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_bits.resize(N / 8 + 1, 0);
		}
		void set(size_t X)
		{
			size_t i = X / 8;
			size_t j = X % 8;
			_bits[i] |= (1 << j);
		}
		void unset(size_t X)
		{
			size_t i = X / 8;
			size_t j = X % 8;
			_bits[i] &= (~(1 << j));
		}
		bool test(size_t X)
		{
			size_t i = X / 8;
			size_t j = X % 8;
			return _bits[i] & (1 << j);
		}
	private:
		std::vector<char> _bits;
	};



	void test_bitset()
	{
		/*bitset<100> bs;
		int array[] = { 1,2,3,4,5,6,7,8,99,78 };
		for (const auto& e : array)
		{
			bs.set(e);
		}
		std::cout<<bs.test(2)<<std::endl;
		std::cout<<bs.test(99)<<std::endl;
		std::cout<<bs.test(78)<<std::endl;
		std::cout<<bs.test(4)<<std::endl;

		bs.unset(2);
		bs.unset(99);
		bs.unset(78);
		bs.unset(4);

		std::cout << bs.test(2) << std::endl;
		std::cout << bs.test(99) << std::endl;
		std::cout << bs.test(78) << std::endl;
		std::cout << bs.test(4) << std::endl;*/
		bitset<-1> bs;
	}

	


}

位图应用

1. 给定 100 亿个整数,设计算法找到只出现一次的整数?
2. 给两个文件,分别有 100 亿个整数,我们只有 1G 内存,如何找到两个文件交集?
3. 位图应用变形: 1 个文件有 100 亿个 int 1G 内存,设计算法找到出现次数不超过 2 次的所有整数

问题1:用两个位图,两个位图可以为00 01 10 

 当一个数第一个位图为0,第二个位图为1,则表明该数只出现一次。

template<size_t N>
	class TwoBitSet
	{
	public:
		void set(size_t x)
		{
			if (_bs1.test(x) == false && _bs2.test(x) == false)  //00 -> 01
			{
				_bs2.set(x);
			}
			else if (_bs1.test(x) == false && _bs2.test(x))   //01  -> 10
			{
				_bs1.set(x);
				_bs2.unset(x);
			}
		}
		void PrintNumOnce()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if (!_bs1.test(i) && _bs2.test(i))
				{
					std::cout << i << std::endl;
				}
			}
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

	void TwoBitSetTest()
	{
		int array[] = { 1,1,2,3,4,5,6,6,7,7,8,8,8,9,9,9,9 };
		TwoBitSet<100> bs;
		for (const auto& e : array)
		{
			bs.set(e);
		}
		bs.PrintNumOnce();
	}
}

 

 

问题2:

思路一:一个文件中的整数,set到一个位图,读取第二个文件中的整数判断在不在位图,在就是交集,不在就不是交集。

void TestFindTest()
	{
		int array1[] = { 1,5,99,6,6,7,10 };
		int array2[] = { 1,8,9,6,7,30,10,40,10,40};
		bitset<100> bs;
		for (const auto e : array1)
		{
			bs.set(e);
		}
		for (const auto e : array2)
		{
			if (bs.test(e))
			{
				std::cout << e << std::endl;
			}
		}
	}

 但是该方法有缺陷:就是第一个文件中的数重复的数会被找出来,还需要去重。

思路二:

一个文件的整数,set到一个位图bs1,另一个文件的整数,set到bs2.

  a.遍历bs2中的值,看在不在bs1中,在就是交集。

void TestFindTest()
	{
		int array1[] = { 1,5,99,6,6,7,10 };
		int array2[] = { 1,8,9,6,7,30,10,40,10,40 };
		bitset<100> bs1;
		bitset<100> bs2;
		for (const auto e : array1)
		{
			bs1.set(e);
		}
		for (const auto e : array2)
		{
			bs2.set(e);
		}

		for (size_t i = 0; i < 100; ++i)
		{
			if (bs1.test(i) && bs2.test(i))
			{
				std::cout << i << std::endl;
			}
		}
	}

 b.两个位图想与,与完是1的位置的值,就是交集。

问题3:

出现1次 00

出现2次 01

出现3次 10

出现4次 11


	template<size_t N>
	class TwoBitSet
	{
	public:
		void set(size_t x)
		{
			if (_bs1.test(x) == false && _bs2.test(x) == false)  //00 -> 01
			{
				_bs2.set(x);
			}
			else if (_bs1.test(x) == false && _bs2.test(x))   //01  -> 10
			{
				_bs1.set(x);
				_bs2.unset(x);
			}
			else if (_bs1.test(x) && _bs2.test(x) == false)   // 10 -> 11
			{
				_bs1.set(x);
				_bs2.set(x);
			}
		}
		void PrintNumOnce()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if (_bs1.test(i))
				{
					std::cout << i << std::endl;
				}
			}
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

	void TwoBitSetTest()
	{
		int array[] = { 1,1,2,3,4,5,6,6,7,7,8,8,8,9,9,9,9 };
		TwoBitSet<100> bs;
		for (const auto& e : array)
		{
			bs.set(e);
		}
		bs.PrintNumOnce();
	}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值