[C++] Aplicación de mapa de bits | Filtro Bloom

1. Aplicación de mapa de bits

tema uno

Dados 4 mil millones de enteros sin signo que no se repiten que no han sido ordenados, y dado un entero sin signo, cómo determinar rápidamente si un número está entre los 4 mil millones de números


Pensamiento normal:
1. Ordenar + búsqueda binaria
2. Ponerlo en una tabla hash o árbol rojo-negro


1000 millones de bytes equivalen aproximadamente a 1 GB
4000 millones de enteros equivalen aproximadamente a 16 GB
Si se utilizan los dos métodos anteriores, la memoria no es suficiente


El mapa hash del método de direccionamiento directo del hash determina si la forma está
presente o no. Mapea la marca a su vez y almacena el valor.
Se usa al menos un carácter para indicar la presencia o ausencia de un valor, que es 4 mil millones bytes o 4 GB, pero aún es demasiado grande
. En ausencia, no hay necesidad de guardar el valor, use 0/1 para representar


Utilice un bit para identificar el valor representado por cada entero, es decir, el mapa de bits
necesita 4 mil millones de bits, mil millones de bytes equivalen aproximadamente a 1 GB y 4 mil millones de bits equivalen aproximadamente a 500 MB.

Código

En la clase de conjunto de bits,
al controlar el carácter, el bit se controla


colocar

set establece el bit de la asignación x en 1

Dado que el subíndice se calcula a partir de 0
, el bit 0-7 se cuenta como el carácter 0 y el 8-15 se cuenta como el primer carácter, que se almacena
primero en el carácter correspondiente y se cuenta en el primer carácter. primeros bits de char



j representa la posición para encontrar el bit correspondiente, y desea establecerlo en 1
<< es un cambio de menor a mayor
1<<j, es decir, todas las posiciones excepto la posición j son 0

Entonces | 1, no importa que el número en esta posición sea 1/0, será 1 después de |

restablecer

rset establece el bit del mapeo x en 0


j significa encontrar la posición del bit correspondiente y desea establecerlo en 0,
entonces &0, independientemente del número de la posición es 1/0, & es 0

prueba

prueba para juzgar si es




j significa buscar la posición del bit correspondiente. El valor de posición actual & 1
es 11 en otras posiciones, por lo que el resultado no es 0, lo que significa que la posición existe.
Si el resultado es 0, significa que la posición no no existe.

código específico

template<size_t N>
class bitset
{
    
    
public:
	bitset()
	{
    
    
		_bits.resize((N / 8) + 1, 0);
	}
	void set(size_t x)
	{
    
    
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] |= (1 << j);
	}
	void rset(size_t x)
	{
    
    
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] &= ~(1 << j);
	}
	bool test(size_t x)//判断在不在
	{
    
    
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		return _bits[i] & (1 << j);
	}
private:
	vector<char> _bits;
};

tema dos

Dados 10 mil millones de enteros, diseñe un algoritmo para encontrar el que ocurre solo una vez.


Use 2 bits para representar los datos actuales
00 significa 0 veces 01 significa 1 vez 10 significa más de 1 vez


Encapsular el código del tema 1



La clase del tema 1 es un conjunto de bits, así que use esto para definir dos bits _bs1 _bs2 Al
juzgar que los dos bits son 1/0,
si el número de ocurrencias es 0, entonces +1 se convierte en 0.
Si el número de ocurrencias es 1, entonces +1 se convierte en 1.
Si el número de ocurrencias de 0 es mayor que 1, permanece sin cambios.Finalmente
, el número que aparece una vez se imprime a través de la función de impresión en la clase.

Resumen de ventajas y desventajas del mapa de bits

ventaja:

velocidad rápida ahorrar espacio

Desventajas:
solo se pueden asignar números enteros y los números de punto flotante de cadena no pueden almacenar asignaciones


Por lo tanto, se propone el filtro Bloom para resolver el problema de que el tipo de cadena no se puede almacenar hasta cierto punto.

2. Filtro de floración

fondo

Desventajas de usar el almacenamiento de tablas hash: desperdicio de espacio

Desventajas de usar el almacenamiento de mapas de bits: los mapas de bits generalmente solo pueden manejar números enteros, pero si son cadenas, no se pueden procesar.La
combinación de hashes con mapas de bits es un filtro Bloom

concepto

El uso de varias funciones hash para mapear una parte de los datos en una estructura de mapa de bits
puede mejorar la eficiencia y ahorrar mucho espacio.


Suponiendo que dos cadenas se asignan a la misma ubicación, provocará una colisión hash.
El filtro Bloom quiere reducir la probabilidad de colisión.
Un valor se asigna a una ubicación, lo que es fácil de juzgar mal. Un valor se asigna a varias ubicaciones. , lo que puede reducir los errores de juicio.


Use una variedad de algoritmos de mapeo hash para mapear a diferentes ubicaciones
Por ejemplo: cada valor se asigna a 2 ubicaciones

Implementación

Al pasar la plantilla, pase hash1 hash2 hash3 para convertir el tipo K en entero
hash1 hash2 hash3 como tres métodos de mapeo diferentes

hash1 hash2 hash3

El algoritmo BKDRHash se ha utilizado en el caso de .
Cuando la cadena deba convertirse en un número entero, agregue todos los caracteres de la cadena para determinar la clave correspondiente. Use
BKDRHash como valor predeterminado y páselo a hash1

Haga clic para ver una explicación detallada: Hash


Pase APHash como valor predeterminado a hash2


Pase DJBHash como valor predeterminado a hash3


El algoritmo APHash y el algoritmo DJBHash se basan en la derivación matemática
Haga clic en el enlace para ver la explicación detallada del algoritmo APHash y el algoritmo DJBHash: Algoritmo hash


problema de valor n

N representa el número máximo de datos clave insertados


k es el número de funciones hash, m es la longitud del filtro bloom y n es el número de elementos insertados

Cuando k es 3, 3= ( m/n ) *0.69, m=4.3n
m es más igual a 4n
La longitud del filtro Bloom es aproximadamente igual a 4 veces el número de elementos insertados


colocar

_bs es la estructura de mapa de bits del tema 1.
Al llamar a diferentes implementaciones de operator() en hash1 hash2 hash3, las
cadenas entrantes correspondientes se convierten en diferentes enteros y los mapas de bits se utilizan para insertarlos en diferentes posiciones de mapeo.


tset

Solo cuando hay tres posiciones diferentes de hash1 hash2 hash3, está allí, si una de las posiciones no está, entonces no está


Incluso si los valores ASCII de las dos cadenas son los mismos, pero el orden es diferente, las posiciones de mapeo correspondientes correspondientes a hash1 hash2 hash3 también son diferentes

¿Es correcto estar en tset o no?

La ausencia es precisa. Cuando está ausente, la posición de mapeo actual es 0. Si los datos existen, es imposible hacer que la posición de mapeo sea 0.


es inexacto,

ts originalmente no existía en la posición de verificación, pero debido a conflictos con otras cadenas, se asignó a la posición de verificación de ts, y se confundiría con la existencia de ts, lo que resultaría en un error de juicio


Escenarios de uso y características

Escenarios que pueden tolerar errores de juicio,
como: determinar rápidamente si se ha utilizado un apodo. El
apodo puede deberse a un error de juicio, lo que puede crear duplicados, pero no tendrá ningún impacto.


Normalmente, el número de teléfono móvil no se puede poner en el filtro Bloom. Si se usa, puede ser mal juzgado. Si no se ha registrado, mostrará que el usuario existe.

inserte la descripción de la imagen aquí

Pero el filtro Bloom también se puede hacer.
Si los datos actuales no están allí, devolverá directamente falso.
Si los datos actuales están allí, puede haber un problema de error de juicio, así que vaya a la base de datos para buscar, si es así, es devolverá directamente los datos existentes, si no, entonces devuelve falso


Características del filtro Bloom
Ventajas: rápido, ahorra memoria
Desventajas: error de juicio (entrada de datos)

código específico

#include<iostream>
using namespace std;
#include<vector>


template<size_t N>
class bitset
{
    
    
public:
	bitset()
	{
    
    	
		_bits.resize((N / 8) + 1, 0);
	}
	void set(size_t x)
	{
    
    
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] |= (1 << j);
	}
	void rset(size_t x)
	{
    
    
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		_bits[i] &= ~(1 << j);
	}
	bool test(size_t x)//判断在不在
	{
    
    
		size_t i = x / 8;//第几个char上
		size_t j = x % 8;//char上的第几个比特位
		return _bits[i] & (1 << j);
	}
private:
	vector<char> _bits;
};

void test_bitset()
{
    
    
	bitset<100> v;
	v.set(10);
	cout << v.test(10) << endl;
	cout << v.test(15) << endl;
}

//仿函数
struct BKDRHash
{
    
    
	size_t operator()(const string& s)
	{
    
    
		size_t hash = 0;
		for (auto e : s)
		{
    
    
			hash += e;
			hash *= 31;
		}
		return hash;
	}
};

struct APHash
{
    
    
	size_t operator()(const string& s)
	{
    
    
		size_t hash = 0;
		for (long i = 0; i < s.size(); i++)
		{
    
    
			size_t ch = s[i];
			if ((i & 1) == 0)
			{
    
    

				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
    
    
				hash ^= (~((hash) << 11) ^ ch ^ (hash >> 5));
			}
		}
		return hash;
	}
};

struct DJBHash
{
    
    
	size_t operator()(const string& s)
	{
    
    
		size_t hash = 5381;
		for (auto e : s)
		{
    
    
			hash += (hash << 5) + e;
		}
		return hash;
	}
};


template< size_t N,
	class K = string,
	class Hash1 = BKDRHash,
	class Hash2 = APHash,
	class Hash3 = DJBHash>
class	BloomFilter  //布隆过滤器
{
    
    
public:
	void set(const K& key)
	{
    
    
		size_t len = N * _X; //整体长度
		//将其转换为可以取模的整型值
		size_t hash1 = Hash1()(key) % len;
		_bs.set(hash1);

		size_t hash2 = Hash2()(key) % len;
		_bs.set(hash2);

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);
	}

	//判断在不在
	bool test(const K& key)
	{
    
    
		size_t len = N * _X; //整体长度

		//三个位置都在才在,有一个位置不在 则不在
		size_t hash1 = Hash1()(key) % len;
		if (!_bs.set(hash1))
		{
    
    
			return false;
		}

		size_t hash2 = Hash2()(key) % len;
		if (!_bs.set(hash2))
		{
    
    
			return false;
		}

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);
		if (!_bs.set(hash3))
		{
    
    
			return false;
		}
		return true;
	}
private:
	static const size_t _X = 4;//整数倍
	bitset<N* _X> _bs;
};

// 一般是字符串才使用 布隆过滤器
// 所以默认使用字符串类型
void test_BloomFilter()
{
    
    
	BloomFilter<100> v;
	v.set("sort");
	v.set("left");
	v.set("right");
	v.set("hello world");
	v.set("test");
	v.set("etst");

}

Supongo que te gusta

Origin blog.csdn.net/qq_62939852/article/details/131015367
Recomendado
Clasificación