<<Алгоритм красивый>>——(1) Общие битовые операции

содержание

1. Битовые операции и основы

2. Несколько интересных битовых операций

3. Используйте n&(n-1)

Одна проблема и три решения: число 1 в двоичном формате

Определить, является ли число показателем степени 2

Небольшой тест

4. Для использования а^а=0

Найдите количество заказов

Небольшой тест

5. Улучшите мышление о битовых операциях

Поменять местами биты четности целого числа

Двоичное представление действительных чисел

Встречается K раз и происходит один раз


1. Битовые операции и основы

Странные приемы для битовых операций:

  • Судейский паритет
  • Получить двоичный бит 1 или 0
  • Поменять местами значения двух целочисленных переменных
  • Найдите абсолютное значение целого числа, не используя оператор суждения
  • Операторы >> и << сдвигают биты вправо или влево
  • >>> оператор заполняет старшие биты 0; >> оператор заполняет старшие биты знаковым битом, нет оператора <<<
  • Для int 1<<35 равно 1<<3
  • И: оба равны 1, результат равен 1; или: один равен 1, результат равен 1; XOR: два не совпадают, результат равен 1
    а б ~ а а&б а|б а^б
    1 1 0 1 1 0
    0 1 1 0 1 1
    0 0 1 0 0 0

2. Несколько интересных битовых операций

| 1. Преобразование английских символов в нижний регистр с помощью операции или  и пробела.


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

2.  Используйте операцию И  & и подчеркивание, чтобы преобразовать английские символы в верхний регистр .

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

3. Используйте операцию XOR  ^ и пробелы, чтобы поменять местами верхний и нижний регистр английских символов.

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

4. Определить, являются ли два числа одного знака

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

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

5. Поменять местами два числа без временных переменных

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

6. Добавьте один

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

7. минус один

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

 ps: Описанную выше операцию можно использовать для чашек перед друзьями, но практической пользы от нее нет.

3. Используйте n&(n-1)

n &(n-1) Эта операция распространена в алгоритмах и устраняет  n последнюю единицу в двоичном представлении числа .

Основная логика заключается в том, что n - 1 должна быть возможность исключить последнюю 1 и в то же время изменить последующие 0 на 1, чтобы операция суммирования  n выполнялась снова  & , и только последнюю 1 можно было превратить в 0.

Вот пример того, как его использовать:

Одна проблема и три решения: число 1 в двоичном формате

 

 Метод 1: целое число n побитовое и 1, то есть n&1 (побитовое и: результат равен 1, чтобы быть 1), когда n выражается в двоичном виде как самая правая 1, тогда n&1 равно 1, count++ один раз, а затем n Двигайтесь вправо >> сравните по одному.

Перейдите непосредственно к коду:

#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;
}

Способ 2: Аналогичен методу, то есть оставить целое число n без изменений и переместить 1 влево; код здесь не приводится, и вам интересно его попробовать.

Метод 3: Используйте n&n(-1), описанный выше, который не будет здесь подробно объясняться, вы можете увидеть выше

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

Определить, является ли число показателем степени 2

 

Если число является показателем степени 2, его двоичное представление должно содержать только одну единицу

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

Если  n & (n-1) используемая техника очень проста (обратите внимание на приоритет операций, нельзя опускать круглые скобки):

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

Небольшой тест

>>>Количество бит 1

>>>Индекс 2 (код заголовка показан выше, если у вас есть вопросы, вы можете обсудить их в комментариях)

4. Для использования а^а=0

Нам нужно помнить о характере операции XOR:

Результатом операции XOR между числом и самим собой является 0, т  . е a ^ a = 0. результатом операции XOR между числом и 0 является оно само, т  a ^ 0 = a. е. .

Найдите количество заказов

Для этого вопроса, пока мы выполняем XOR всех чисел, парные числа станут 0. XOR одного числа и 0 по-прежнему остается самим собой, поэтому окончательный результат XOR — это элемент, который появляется только один раз. :

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

Небольшой тест

>>> число, которое появляется только один раз

5. Улучшите мышление о битовых операциях

Поменять местами биты четности целого числа

Обмен паритетом целых чисел здесь на самом деле является обменом битов паритета на двоичный. Вместо замены четности на десятичное число 15 замените его на 51. Например, замените 1010 на 0101;

Идея: введите целое число, сделайте его побитовым и 010101... сохраните значение четного числа как ou (это предложение требует вкуса), а затем сделайте его побитовым и 101010... сохраните нечетное значение как ji, затем переместите ou влево << один бит, ji вправо >> один бит, а затем XOR для достижения желаемой цели. 

Код:

#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;
}

двоичное представление действительных чисел с плавающей запятой

Код:

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;
}

Встречается K раз и происходит один раз

Прорыв в решении проблемы: вывод о том, что результат равен 0, с помощью k K-арных чисел для сложения без переноса

Сначала преобразуйте десятичное число в k-арное и используйте строку для хранения в обратном
порядке.Используйте метод остатка от деления на k (общий метод вычисления), чтобы преобразовать число в массиве в k-ичное число.

Поскольку его нужно вычислять по битам (столбцам) после преобразования в k-ary, он хранится в виде строки. После перевода в k-ичную систему из-за разного размера чисел длина тоже может быть разной.Хотя для чисел с k цифрами сумма равна 0, разницы нет, но последовательность битов очень важна для требуемого число, (вычисление. Когда строка вычисляется слева направо, а при обратном преобразовании в десятичную она вычисляется справа налево), поэтому числа, преобразованные в k-основание, сохраняются в обратном порядке .

Найдите максимальную длину строки, а затем заполните строку, которая меньше, чем maxlen.Поскольку
ее нужно вычислять столбец за столбцом, необходимо знать, сколько столбцов не более, то есть maxlen. Заполните «0» в старшем порядке, составьте длину maxlen, чтобы выполнить побитовое сложение без переноса

Сложение без переноса
Сложите эти числа без переноса, что эквивалентно операции XOR ^, или возьмите число после побитового сложения по модулю k

Выходной результат, K-арный в десятичный
Этот шаг прост, принцип тот же, что и при обычном преобразовании восьмеричного в десятичный и шестнадцатеричного в десятичный.

#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;
}

рекомендация

отblog.csdn.net/m0_58367586/article/details/123705689