Directorio de artículos
Introducción al conjunto de bits
La introducción de mapas de bits
Da 4 mil millones de enteros únicos sin signo, sin clasificar. Dado un entero sin signo, ¿cómo determinar rápidamente si un número se encuentra entre los 4 mil millones de números?
Para determinar si un número está en un cierto montón, podemos pensar en los siguientes métodos:
- Ordene esta pila de números y luego use el método de búsqueda binaria para determinar si el número está en esta pila de números.
- Inserte esta pila de números en el contenedor unordered_set y luego llame a la función de búsqueda para determinar si el número está en esta pila de números.
Desde el punto de vista del método, ambos métodos son posibles y la eficiencia también es buena. La complejidad temporal del primer método es O ( N log N ) O (NlogN)O ( N l o g N ) , la complejidad temporal del segundo método esO ( N ) O(N)O ( N ) _
Pero el problema es que aquí hay 4 mil millones de números. Si queremos cargar todos estos números en la memoria, ocupará 16 G de espacio y el consumo de espacio es muy grande. Por lo tanto, desde la perspectiva del consumo de espacio, los dos métodos anteriores son realmente inviables.
resolución de mapa de bits
De hecho, en este problema, solo necesitamos juzgar si un número está presente o no, es decir, solo hay dos estados, entonces podemos usar un bit para indicar si los datos existen, si el bit es 1, significa existe, y el bit es 0. Indica que no existe. Por ejemplo, hay 232
enteros sin signo en total , por lo que registrar estos números requiere 232 bits, lo que equivale a 512 M de espacio de memoria, y el consumo de memoria se reduce considerablemente.
concepto de mapa de bits
El llamado mapa de bits consiste en usar cada bit para almacenar un determinado estado, lo cual es adecuado para escenarios con datos masivos y sin repetición de datos. Por lo general, se utiliza para determinar si un determinado dato existe o no.
aplicaciones de mapa de bits
Las aplicaciones comunes de mapa de bits son las siguientes:
- Encuentre rápidamente si un dato está en una colección.
- clasificar.
- Encuentra la intersección, unión, etc. de dos conjuntos.
- Marca de bloque de disco en el sistema operativo.
- Bits de marca de señal en el kernel (palabra de máscara de señal y conjunto de señal pendiente).
uso de conjunto de bits
Cómo se define un conjunto de bits
Método 1: construya un mapa de bits de 16 bits, todos los bits se inicializan en 0.
bitset<16> bs1; //0000000000000000
Método 2: construya un mapa de bits de 16 bits e inicialice los primeros n bits del mapa de bits de acuerdo con el valor dado.
bitset<16> bs2(0xfa5); //0000111110100101
Método 3: construya un mapa de bits de 16 bits e inicialice los primeros n bits del mapa de bits de acuerdo con la secuencia 0/1 en la cadena.
bitset<16> bs3(string("10111001")); //0000000010111001
Uso de funciones miembro de conjunto de bits
Las funciones miembro comúnmente utilizadas en el conjunto de bits son las siguientes:
función miembro | Función |
---|---|
colocar | Establecer el bit especificado o todos los bits |
Reiniciar | Borrar bit especificado o todos los bits |
dar la vuelta | Invertir bits especificados o todos los bits |
prueba | Obtener el estado del bit especificado |
contar | Obtener el número de bits que se establecen |
Talla | Obtener el número de bits que se pueden acomodar |
ninguna | Devuelve verdadero si alguno de los bits está establecido |
ninguna | Devuelve verdadero si no se establece ningún bit |
todos | Devuelve verdadero si todos los bits están establecidos |
Ejemplo de uso:
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bs;
bs.set(2); //设置第2位
bs.set(4); //设置第4位
cout << bs << endl; //00010100
bs.flip(); //反转所有位
cout << bs << endl; //11101011
cout << bs.count() << endl; //6
cout << bs.test(3) << endl; //1
bs.reset(0); //清空第0位
cout << bs << endl; //11101010
bs.flip(7); //反转第7位
cout << bs << endl; //01101010
cout << bs.size() << endl; //8
cout << bs.any() << endl; //1
bs.reset(); //清空所有位
cout << bs.none() << endl; //1
bs.set(); //设置所有位
cout << bs.all() << endl; //1
return 0;
}
Nota: Cuando se utilizan las funciones miembro set, reset y flip, si se especifica un determinado bit, se opera el bit, y si no se especifica ningún bit, se operan todos los bits.
Uso del operador de conjunto de bits
1. El uso de los operadores >> y << en el conjunto de bits.
El contenedor de conjuntos de bits sobrecarga los operadores >> y << Podemos usar directamente los operadores >> y << para realizar operaciones de entrada y salida en los objetos definidos por el contenedor de conjuntos de bits.
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bs;
cin >> bs; //10110
cout << bs << endl; //00010110
return 0;
}
En segundo lugar, el uso de operadores de asignación, operadores relacionales, operadores de asignación compuestos y operadores unarios en conjuntos de bits.
En el contenedor de conjunto de bits, no solo el operador de asignación y algunos operadores relacionales están sobrecargados, sino también algunos operadores de asignación compuestos y operadores unarios están sobrecargados, y podemos usar directamente estos operadores para operar en mapas de bits individuales.
Incluye los siguientes operadores:
- Operador de asignación: =.
- Operadores relacionales: ==, !=.
- Operadores de asignación compuestos: &=, |=, ^=, <<=, >>=.
- Operador unario: ~.
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bs1(string("10101010"));
bitset<8> bs2(string("10101010"));
bs1 >>= 1;
cout << bs1 << endl; //01010101
bs2 |= bs1;
cout << bs2 << endl; //11111111
return 0;
}
3. El uso de operadores bit a bit en conjunto de bits.
Los tres operadores de bits también están sobrecargados en el contenedor de conjuntos de bits.Podemos usar directamente &, |, ^ para operar en cada mapa de bits.
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bs1(string("10101010"));
bitset<8> bs2(string("01010101"));
cout << (bs1&bs2) << endl; //00000000
cout << (bs1|bs2) << endl; //11111111
cout << (bs1^bs2) << endl; //11111111
return 0;
}
Cuarto, el uso del operador [ ] en el conjunto de bits.
El operador [ ] está sobrecargado en el contenedor del conjunto de bits, y podemos usar directamente [ ] para acceder o modificar el bit especificado.
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
int main()
{
bitset<8> bs(string("00110101"));
cout << bs[0] << endl; //1
bs[0] = 0;
cout << bs << endl; //00110100
return 0;
}