<<El algoritmo es hermoso>>——(1) Operaciones de bits comunes

contenido

1. Operaciones con bits y bases

2. Varias operaciones de bits interesantes

3. Usa n&(n-1)

Un problema y tres soluciones: el número 1 en binario

Determinar si un número es un exponente de 2

una pequeña prueba

4. Para usar a ^ a = 0

Encuentre el número de pedidos

una pequeña prueba

5. Mejorar el pensamiento de operación de bit

Intercambiar los bits de paridad de un entero

Representación binaria de números

Ocurre K veces y Ocurre una vez


1. Operaciones con bits y bases

Extraños trucos para operaciones con bits:

  • Juzgando la paridad
  • Obtener bit binario es 1 o 0
  • Intercambiar los valores de dos variables enteras
  • Encuentre el valor absoluto de un número entero sin usar una declaración de juicio
  • Los operadores >> y << desplazan los bits a la derecha o a la izquierda
  • >>> el operador llenará los bits altos con 0; >> el operador llena los bits altos con el bit de signo, sin operador <<<
  • Para int, 1<<35 es lo mismo que 1<<3
  • AND: ambos son 1, el resultado es 1; o: uno es 1, el resultado es 1; XOR: los dos no son iguales, el resultado es 1
    a B ~ un a&b a|b a ^ b
    1 1 0 1 1 0
    0 1 1 0 1 1
    0 0 1 0 0 0

2. Varias operaciones de bits interesantes

| 1. Convierta caracteres ingleses a minúsculas usando u operación  y espacio


('a' | ' ') = 'a'
('A' | ' ') = 'a'

2.  Use la operación AND  & y el guión bajo para convertir caracteres ingleses a mayúsculas

('b' & '_') = 'B'
('B' & '_') = 'B'

3. Use la operación XOR  ^ y los espacios para intercambiar mayúsculas y minúsculas de caracteres ingleses

('d' ^ ' ') = 'D'
('D' ^ ' ') = 'd'

4. Determinar si dos números son del mismo signo

int x = -1, y = 2;
boolean f = ((x ^ y) < 0); // true

int x = 3, y = 2;
boolean f = ((x ^ y) < 0); // false

5. Intercambia dos números sin variables temporales

int a = 1, b = 2;
a ^= b;
b ^= a;
a ^= b;
// a = 2, b = 1

6. Agrega uno

int n = 1;
n = -~n;
//  n = 2

7. menos uno

int n = 2;
n = ~-n;
//  n = 1

 pd: la operación anterior se puede usar para copas frente a amigos, pero no tiene ningún uso práctico.

3. Usa n&(n-1)

n &(n-1) Esta operación es común en los algoritmos y actúa para eliminar  n el último 1 en la representación binaria de un número .

La lógica central es que n - 1 debe ser posible eliminar el último 1 y, al mismo tiempo, cambiar los 0 subsiguientes en 1, de modo que la operación de suma  se n realice nuevamente  & , y solo el último 1 se pueda convertir en 0.

Aquí hay un ejemplo de cómo usarlo:

Un problema y tres soluciones: el número 1 en binario

 

 Método 1: el entero n es bit a bit y 1, es decir, n&1, (bit a bit y: el resultado es 1 para ser 1), cuando n se expresa en binario como el 1 más a la derecha, entonces n&1 es 1, cuenta ++ una vez, y luego n Mover a la derecha >> comparar uno por uno.

Ir directamente al código:

#include<stdio.h>
int main()
{
	int n;
	int ants = 0;
	scanf("%d",&n);
	for (int i = 0; i < 32; i++)
	{
		int m = n;
		if ((m>>i)&1== 1)
			ants++;
	}
	printf("%d", ants);
	return 0;
}

Método 2: similar al método, es decir, mantenga el número entero n sin cambios y mueva 1 a la izquierda; el código no se proporciona aquí y le interesa probarlo.

Método 3: use el n&n(-1) explicado anteriormente, que no se explicará en detalle aquí, puede ver lo anterior

int hammingWeight(int n) {
    int res = 0;
    while (n != 0) {
        n = n & (n - 1);
        res++;
    }
    return res;
}

Determinar si un número es un exponente de 2

 

Si un número es un exponente de 2, su representación binaria debe contener solo un 1

2^0 = 1 = 0b0001
2^1 = 2 = 0b0010
2^2 = 4 = 0b0100

Si  n & (n-1) la técnica utilizada es muy simple (tenga en cuenta la precedencia del operador, los paréntesis no se pueden omitir):

boolean isPowerOfTwo(int n) {
    if (n <= 0) return false;
    return (n & (n - 1)) == 0;
}

una pequeña prueba

>>>Número de bits 1

>>>El índice de 2 (el código del título se muestra arriba, si tiene alguna pregunta, puede discutirla en el área de comentarios)

4. Para usar a ^ a = 0

La naturaleza de la operación XOR es algo que debemos tener en cuenta:

El resultado de la operación XOR entre un número y sí mismo es 0, es decir  a ^ a = 0, el resultado de la operación XOR entre un número y 0 es él mismo, es decir  a ^ 0 = a.

Encuentre el número de pedidos

Para esta pregunta, mientras hacemos XOR todos los números, los números emparejados se convertirán en 0. El XOR del número único y 0 sigue siendo el mismo, por lo que el resultado final de XOR es el elemento que solo aparece una vez:

int singleNumber(int[] nums) {
    int res = 0;
    for (int n : nums) {
        res ^= n;
    }
    return res;
}

una pequeña prueba

>>> un número que solo aparece una vez

5. Mejorar el pensamiento de operación de bit

Intercambiar los bits de paridad de un entero

El intercambio de paridad de enteros aquí es en realidad el intercambio de bits de paridad en binario. En lugar del intercambio de paridad en decimal, 15, reemplácelo con 51. Por ejemplo, reemplace 1010 con 0101;

Idea: ingrese un número entero, hágalo bit a bit y 010101... mantenga el valor del número par como ou (esta oración necesita gusto), y luego hágalo bit a bit y 101010... mantenga el valor impar como ji, luego mueva ou a la izquierda << un bit, ji a la derecha >> un bit, y luego XOR para lograr el propósito deseado. 

Código:

#include<stdio.h>
int main()
{
	int n;
	scanf("%d",&n);
	int ji = n & 0xaaaaaaaa;//1010...
	int ou = n & 0x55555555;//0101...
    int c= (ou << 1) ^(ji >> 1);
	printf("%d",c);
	return 0;
}

representación binaria de números reales de punto flotante

Código:

0.625 0.5+0.125
0.101
#include<iostream>
using namespace std;
int main()
{
	double n;
	cin >> n;
	string s1 = "0.";
	while (n > 0)
	{
		n= n * 2;
		if (n >=1)
		{
			s1 +="1";
			n = n - 1;
		}
		else {
			s1 += "0";
			n = n;
		}
		if (s1.size() > 34)
		{
			cout << "ERROR " << endl;
		}
	}
	cout << s1 << endl;
	return 0;
}

Ocurre K veces y Ocurre una vez

El gran avance para resolver el problema: la conclusión de que el resultado es 0 usando k números K-arios para sumar sin llevar

Primero convierta el número decimal a k-ario, y use la cadena para almacenar en orden
inverso.Use el método de resto de dividir por k (un método de cálculo general) para convertir el número en la matriz a k-ario.

Debido a que debe calcularse por bit (columna) después de la conversión a k-ario, se almacena en forma de cadena. Después de la conversión al sistema k-ario, debido a los diferentes tamaños de los números, las longitudes también pueden ser diferentes. Aunque la suma es 0 para números con k números, no hay diferencia, pero la secuencia de bits es muy importante para el requerido número, (cálculo Cuando la cadena se calcula de izquierda a derecha, y cuando se vuelve a convertir a decimal, se calcula de derecha a izquierda), por lo que los números convertidos a k-base se almacenan en orden inverso .

Encuentre la longitud máxima de la cadena y luego complete la cadena que es menor que maxlen.
Debido a que debe calcularse columna por columna, es necesario saber cuántas columnas hay como máximo, es decir, maxlen. Rellene "0" en el orden superior, compense la longitud máxima, para hacer una suma poco a poco sin llevar

Suma sin acarreo
Suma estos números sin acarreo, que es equivalente a la operación XOR ^, o toma el número después de la suma bit a bit módulo k

Resultado de salida, K-ario a decimal
Este paso es simple, el mismo principio que el común octal a decimal y hexadecimal a decimal.

#include<iostream>
#include<algorithm>
#include<string>
//#include<cmath>
using namespace std;
string decTok(int dec, int k); //十进制数转K进制 
int kTodec(string str, int k); // K进制转十进制

string decTok(int dec, int k) 
{
	string ret = "";  //作为结果
	while (dec > 0) {
		ret += char(dec%k + '0');//如:5+'0'='5' 
		dec /= k;
	}
	reverse(ret.begin(), ret.end());//翻转
	return ret;
}

int kTodec(string str, int k) 
{
	int ans = 0;
	for (int i = 0; i < str.size(); i++)
		ans = ans * k + (str[i] - '0');//020 首位是最高位 
	return ans;
}

int main() 
{
	int n[] = { 1,1,1,3,3,3,5,5,5,9,9,9,6,7,7,7 };
	int k = 3; //根据数组数据,要转换的进制 

	//1.十进制数转K进制 
	string str[16];
	for (int i = 0; i < 16; i++)
		str[i] = decTok(n[i], k);

	//2.找出16条字符串中最大长度
	int maxlen = 0;
	int len;
	for (int i = 0; i < 16; i++) {
		len = str[i].size();
		maxlen = max(maxlen, len); //maxlen=max(maxlen,str[i].size())
	}
	//16条字符串中,若字符串长度<maxlen,则进行补齐,以便逐位做不进位加法
	for (int i = 0; i < 16; i++)
		while (str[i].size() < maxlen)
			str[i] = "0" + str[i];

	//ans:结果初始化 
	string ans = "";
	while (ans.size() < maxlen)
		ans += "0";

	//3.做不进位加法
	for (int i = 0; i < 16; i++)
		for (int j = 0; j < maxlen; j++)
			ans[j] = char(((str[i][j] - '0') + (ans[j] - '0')) % k + '0');

	cout << ans << endl; //ans字符串结果
	cout<< kTodec(ans, k); //转为十进制数 
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/m0_58367586/article/details/123705689
Recomendado
Clasificación