<<The algorithm is beautiful>>——(1) Common bit operations

content

1. Bit operations and bases

2. Several interesting bit operations

3. Use n&(n-1)

One problem and three solutions: the number of 1 in binary

Determine if a number is an exponent of 2

A small test

4. For use a ^ a = 0

Find the number of orders

A small test

5. Improve bit operation thinking

Swap the parity bits of an integer

Binary representation of floating point real numbers

Occurs K times and Occurs once


1. Bit operations and bases

Strange tricks for bit operations:

  • Judging parity
  • Get binary bit is 1 or 0
  • Swap the values ​​of two integer variables
  • Find the absolute value of an integer without using a judgment statement
  • >> and << operators shift bits to the right or left
  • >>> operator will fill high bits with 0; >> operator fills high bits with sign bit, no <<< operator
  • For int, 1<<35 is the same as 1<<3
  • AND: both are 1, the result is 1; or: one is 1, the result is 1; XOR: the two are not the same, the result is 1
    a b ~a 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. Several interesting bit operations

| 1. Convert English characters to lowercase using or operation  and space


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

2.  Use AND operation  & and underscore to convert English characters to uppercase

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

3. Use XOR operation  ^ and spaces to exchange upper and lower case of English characters

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

4. Determine whether two numbers are of the same sign

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

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

5. Swap two numbers without temporary variables

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

6. Add one

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

7. minus one

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

 ps: The above operation can be used for cups in front of friends, but it has no practical use.

3. Use n&(n-1)

n &(n-1) This operation is common in algorithms and acts to eliminate  n the last 1 in the binary representation of a number .

The core logic is that it n - 1 must be possible to eliminate the last 1, and at the same time change the subsequent 0s into 1s, so that the sum  operation is n performed again  & , and only the last 1 can be turned into 0.

Here's an example of how to use it:

One problem and three solutions: the number of 1 in binary

 

 Method 1: The integer n is bitwise and 1, that is, n&1, (bitwise and: the result is 1 to be 1), when n is expressed in binary as the rightmost 1, then n&1 is 1, count++ once, and then n Move to the right >> compare one by one.

Go directly to the code:

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

Method 2: Similar to the method, that is, keep the integer n unchanged and move 1 to the left; the code is not provided here, and you are interested in trying it.

Method 3: Use the n&n(-1) explained above, which will not be explained in detail here, you can see the above

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

Determine if a number is an exponent of 2

 

If a number is an exponent of 2, its binary representation must contain only one 1

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

If  n & (n-1) the technique used is very simple (note the operator precedence, the parentheses cannot be omitted):

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

A small test

>>>Number of bit 1s

>>>The index of 2 (the title code has been shown above, if you have any questions, you can discuss it in the comment area)

4. For use a ^ a = 0

The nature of the XOR operation is something we need to keep in mind:

The result of XOR operation between a number and itself is 0, ie  a ^ a = 0; the result of XOR operation between a number and 0 is itself, ie  a ^ 0 = a.

Find the number of orders

For this question, as long as we XOR all the numbers, the paired numbers will become 0. The XOR of the single number and 0 is still itself, so the final XOR result is the element that only appears once. :

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

A small test

>>> a number that only appears once

5. Improve bit operation thinking

Swap the parity bits of an integer

The parity swap of integers here is actually the swap of parity bits on binary. Instead of the parity swap on decimal, 15, replace it with 51. For example, replace 1010 with 0101;

Idea: input an integer, make it bitwise and 010101... keep the value of the even number as ou (this sentence needs taste), and then make it bitwise and 101010... keep the odd value as ji , then move ou to the left << one bit, ji to the right >> one bit, and then XOR it to achieve the desired purpose. 

Code:

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

binary representation of floating point real numbers

Code:

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

Occurs K times and Occurs once

The breakthrough of solving the problem: the conclusion that the result is 0 by using k K-ary numbers to add without carry

First convert the decimal number to k-ary, and use the string to store in reverse order.
Use the remainder method of dividing by k (a general calculation method) to convert the number in the array to k-ary number.

Because it needs to be calculated by bit (column) after conversion to k-ary, it is stored in the form of a string. After conversion to k-ary system, due to the different sizes of the numbers, the lengths may also be different. Although the sum is 0 for numbers with k numbers, there is no difference, but the bit sequence is very important for the required number, (calculation When the string is calculated from left to right, and when converted back to decimal, it is calculated from right to left), so the numbers converted to k-base are stored in reverse order .

Find the maximum length of the string, and then fill in the string that is less than maxlen.
Because it needs to be calculated column by column, it is necessary to know how many columns there are at most, that is, maxlen. Fill "0" in the high order, make up the maxlen length, so as to do bit-by-bit addition without carry

Add without carry
Add these numbers without carry, which is equivalent to the XOR operation ^, or take the number after the bitwise addition modulo k

Output result, K-ary to decimal
This step is simple, the same principle as the common octal-to-decimal and hexadecimal-to-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;
}

Guess you like

Origin blog.csdn.net/m0_58367586/article/details/123705689