Implementación de mapa de bits y mapa de bits de C++

concepto

Mapa de bits es la abreviatura de mapa de bits. El llamado mapa de bits es usar cada bit para almacenar un cierto estado, que es adecuado para datos a gran escala. Los datos son datos simples que no se repiten. Por lo general, se utiliza para juzgar si un determinado dato existe o no.

Por ejemplo: dados 4 mil millones de enteros enteros sin signo que no se repiten, que no han sido ordenados, y luego damos un número, ¿cómo determinar rápidamente si este número está entre los 4 mil millones de números? Si no miramos la cantidad de datos , nuestro primer
pensamiento Debe recorrerse desde el principio, pero la cantidad de datos es muy grande, hay 4 mil millones, y el tiempo y la memoria consumidos al atravesar 4 mil millones de veces son muy grandes. Pero después de introducir el mapa de bits, el problema de si existe una cantidad tan grande de búsqueda de datos puede resolverse específicamente. La complejidad de tiempo para encontrar si este número existe es O(1) y ahorra 32 veces la capacidad (se explica a continuación). Echemos un vistazo al principio y la implementación del código del mapa de bits.

principio

Para saber si un número existe, la respuesta es si existe o no. Este tipo de preguntas que solo necesitan responder sí o no se pueden representar con bits en binario. 1 significa que el número existe y 0 significa que el número no existe. Y cada unidad de datos en el mapa de bits es un bit. De esta manera, normalmente necesitamos almacenar datos en 32 bits y 4 bytes, pero ahora solo necesitamos gastar 1 byte para "almacenar datos". La capacidad se reduce en aproximadamente 32 veces. Por ejemplo, solo necesitamos gastar 1.3G para almacenar datos de 40G. Pero el tipo de datos mínimo que normalmente operamos es un byte, no podemos operar directamente con bits, por lo que podemos usar operaciones de bits para operar con datos. Echemos un vistazo a cómo se almacenan los datos en el mapa de bits.
Aquí damos una matriz
int arr[] = {1,2,4,5,7,10,11,14,16,17,21,23, 24 , 28, 29, 31}; entonces solo necesitamos gastar 1 byte para almacenar estos datos.
inserte la descripción de la imagen aquí
Explicación: muchas de nuestras máquinas actuales se almacenan en little endian, es decir, las direcciones bajas se almacenan en bits bajos. En datos enteros, el primero El byte se usa para almacenar los números 0-7, el segundo byte se usa para almacenar los números 8-15, el tercer byte se usa para almacenar los números 16-23, y el cuarto byte se usa para almacenar los números 24-31 números. Veamos cómo se almacena el número 10. Primero pase el módulo de 32, el resto sigue siendo 10, y luego establezca el décimo bit en los 4 bytes a 1, lo que indica que el número ha aparecido. Dado que nuestra máquina es un almacenamiento little-endian, cada uno de nuestros bits debe calcularse desde la derecha, como se muestra en la figura a continuación, por lo que
inserte la descripción de la imagen aquí
solo necesitamos establecer la posición del bit correspondiente en 1. Pero, ¿y si los datos que queremos almacenar son enormes? De hecho, también es muy simple. Podemos definir una matriz como un mapa de bits. Si el número está entre 0 y 31, lo almacenaremos en el elemento del subíndice 0 y lo operaremos. Si está entre 32 y 63, entonces estará en Operar entre los subíndices No. 1. Cálculo del subíndice Podemos obtener el subíndice por módulo 32.

Después de conocer el principio del mapa de bits, implementemos un mapa de bits con código a través del principio

lograr

Variables miembro y constructores : al implementar mapas de bits, nuestras variables miembro solo necesitan una matriz para implementar. ¿Y qué tan grande es esta matriz, qué tan grande queremos abrirla? Abrir un espacio entero adicional en la matriz puede almacenar 32 números más, por lo que podemos permitir que los usuarios proporcionen un número preciso.Este número es un volumen de datos y el rango máximo del número. Podemos obtener el tamaño del arreglo por módulo 32, pero 0~31 módulo 32 es 0, obviamente es inapropiado para nosotros abrir un espacio de 0, entonces necesitamos abrir un arreglo del tamaño del range/32 + 1espacio

Almacenamiento de datos : almacenar un número num requiere pasos 3. El primero es calcular el subíndice de la matriz correspondiente al valor. La forma de calcular el subíndice de la matriz es idx=num / 32; el segundo paso es calcular la posición de bit de num en el entero correspondiente bitIdx=num%32; el tercer paso es establecer la posición de bit calculada en 1. Como dijimos antes, para manipular bits, podemos operar a través de operaciones de bits, primero desplazar 1 a la izquierda por bitIdx y luego realizar una operación OR con un número entero. Por ejemplo, supongamos que bitIdx=5, el dato es 10010011 1. Desplazar
1
a la izquierda por 5 bits ==>100000
2. O los datos y el resultado calculado en el primer paso
10010011 | 100000 =10110011, luego estableceremos la posición especificada en 1

Encontrar datos : para juzgar si existen datos, en realidad es similar a almacenar datos, y también necesita calcular dos posiciones idx y bitIdx. Luego use estas dos posiciones para juzgar si la posición correspondiente es 1, y si es 1, significa que el número existe. ¿Cómo juzgar? Primero podemos cambiar el entero subíndice como idx a la derecha por bitIdx, y luego realizar una operación AND con 1. Si es 1, significa que existe, de lo contrario no existe. Por ejemplo, supongamos que bitIdx = 5, y
el los datos son 10110011
1. Desplazamiento a la derecha 5 bits 00000101
2. Realice una operación AND en el resultado calculado en el primer paso y 1.
00000101 & 1 = 1, lo que significa que el número existe y devuelve verdadero

Eliminar datos : la operación de eliminar datos es la misma que la de almacenar datos, la única diferencia es que la posición del bit correspondiente se establece en 0. Primero podemos desplazar 1 a la izquierda por bitIdx, luego invertir, y luego Y el resultado con los datos originales.Por
ejemplo, supongamos que bitIdx=5, los datos son 10110011
1. Desplace 1 a la izquierda por 5 bits e invierta 011111
2 Realice la operación AND sobre el resultado calculado en el primer paso y los datos
10110011 y 011111 = 10010011, la eliminación es exitosa

código :

class BitMap
{
    
    
public:
	//位图的内存大小和数据范围有关
	BitMap(size_t range)
		:_bit(range / 32 + 1)
	{
    
    }

	void set(const size_t num)
	{
    
    
		//计算数组中的下标
		int idx = num / 32;
		//计算num在对应下标整数中的下标位置
		int bitIdx = num % 32;
		//将对应的比特位置1
		_bit[idx] |= 1 << bitIdx;
	}

	bool find(const size_t num)
	{
    
    
		int idx = num / 32;
		int bitIdx = num % 32;
		return (_bit[idx] >> bitIdx) & 1;
	}

	void reset(const size_t num)
	{
    
    
		int idx = num / 32;
		int bitIdx = num % 32;
		_bit[idx] &= ~(1 << bitIdx);
	}
private:
	vector<int> _bit;
};

Prueba de captura de pantalla:
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_44443986/article/details/117359908
Recomendado
Clasificación