1 十进制,八进制和十六进制
2 原码,反码和补码
在内存中,数据以二进制的方式存储,且最小单位是字节。对于有符号的数值,无论正反,计算机都是以补码的形式进行存储。
1)正数的原码,反码和补码都相同。
以整型数字4为例:
原码:00000000 00000000 00000000 00000100
反码:00000000 00000000 00000000 00000100
补码:00000000 00000000 00000000 00000100
2)负数的反码为原码除符号位外各位取反,补码是反码最后一位加1。
以整型数字-1为例:
原码:10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110
补码:11111111 11111111 11111111 11111111
3 位运算符
/**
* Created by JayLai on 23/11/2018
*/
public class BitwiseApp {
public static void main(String[] args) {
int a = 4;
int b = -1;
/**
* 数据在内存中以二进制形式的补码存储,正数以0开头,负数以1开头
* a: 00000000 00000000 00000000 00000100
* b: 11111111 111111111 1111111 11111111
*/
System.out.println(Integer.toBinaryString(a));
System.out.println(Integer.toBinaryString(b));
/**
* int类型的取值范围: [-2^31 ~ 2^31 -1]
* 计算原理:
* 无符号情况下,算上值为0,32位二进制数一共有 2^32个
* 正整数情况下,由等比数列计算出最大值为2 ^31 -1
* 因此负数的最小值为-^31
*/
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
/**
* 按位与运算
* 两个操作数对应位数都是1结果位才是0,否则是0
*/
System.out.println(a & b);
/**
* 按位或运算
* 两个操作数对应位数都是0结果位才是0,否则是1
*/
System.out.println(a | b);
/**
* 按位非运算
* 将操作数二进制的所有位数全部取反
*/
System.out.println(~a);
System.out.println(~b);
/**
* 按位异或运算
* 两个操作数对应位数相同为0,否则为1,符号位也要取反
*/
System.out.println(a ^ b);
/**
* 左移运算符
* 操作数的二进制数据向左移动指定位数,空缺部分补0
* 左移n位后的值 等于原值乘以2的n次方
*/
System.out.println(a << 2);
System.out.println(b << 2);
/**
* 右移动运算符
* 操作数的二进制数据向右移动指定位数,符号为是1,则右边空缺补充1,否在补0
* 右移n位后的值 等于原值除以2的n次方的商
*/
System.out.println(a >> 2);
System.out.println(b >> 2);
/**
* 无符号右移
* 不管正负标志位为0还是1,将该数的二进制码整体右移,左边部分总是以0填充,右边部分舍弃
*/
System.out.println(a >>> 2);
System.out.println(b >>> 2);
}
}
4 位运算常见算法题目
4.1 统计二进制数中含有1的个数
请实现一个函数,输入一个整数,输出该树二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2.
1)实现代码
/**
* Created by JayLai on 11/12/2018
*/
public class NumberOf1App {
/**
* 字符串
* 缺点:效率低
* @param input
*/
public static void method1(int input) {
String str = Integer.toBinaryString(input) + "";
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '1') {
count++;
}
}
System.out.println(count);
}
/**
* 左移到运算
* 缺点:需要循环32次
* @param input
*/
public static void method2(int input) {
int count = 0;
int flag = 1;
for (int i = 0; i < 32; i++) {
if ((input & flag) != 0)
count++;
flag = flag << 1;
}
System.out.println(count);
}
/**
* 右移运算
* 缺点:只适用于正整数,负数出现死循环
* @param input
*/
public static void method3(int input) {
int count = 0;
while (input != 0) {
if ((input & 1) == 1)
count++;
input = input >> 1;
}
System.out.println(count);
}
/**
* 无符号右移运算
* @param input
*/
public static void method4(int input) {
int count = 0;
while (input != 0) {
if ((input & 1) == 1)
count++;
input = input >>> 1;
}
System.out.println(count);
}
/**
* 移位运算
* 思路:使最右边一个1变为0,不断重复直到所有1变为0
* @param input
*/
public static void method5(int input) {
int count = 0;
while (input != 0) {
input = input & (input - 1);
count++;
}
System.out.println(count);
}
public static void main(String[] args) {
int[] numArray = {0, 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF};
for (int num: numArray
) {
method1(num);
method2(num);
// method3(num);
method4(num);
method5(num);
}
}
}
2)测试结果
4.2判断一个正整数是不是2的整数次方
1)代码实现
/**
* Created by JayLai on 16/11/2018
*/
public class PowerOf2App {
public static void method1(int input){
int flag = 1;
while (input >= flag){
if(input == flag){
System.out.println(input + "是2的整数次方");
return;
}
flag = flag << 1;
}
System.out.println(input + "不是2的整数次方");
}
public static void method2(int input){
int ret = input & (input - 1);
if( ret == 0){
System.out.println(input + "是2的整数次方");
}else {
System.out.println(input + "不是2的整数次方");
}
}
public static void main(String[] args) {
int flag = 1;
for(int i = 1; i < 10; i++){
method1(flag);
method2(flag);
flag *= 2;
}
}
}
2)测试结果
4.3 输入两个整数m和n,计算需要改变m的二进制表示中的多少为才能得到n
1)实现代码
/**
* Created by JayLai on 16/11/2018
*/
public class NUmOfChangeApp {
/**
* 先异或,再求二进制数中1的个数
* @param m
* @param n
*/
public static void method1(int m, int n) {
int input= m ^ n;
int count = 0;
while (input != 0) {
input = input & (input - 1);
count++;
}
System.out.println("需要改变" + m + "的二进制表示中的"+ count +"位才能得到" + n);
}
public static void main(String[] args) {
method1(10, 13);
}
}
2)测试结果
4.4 交换2个变量a和b,不能创建临时变量
1)实现代码
/**
* Created by JayLai on 16/11/2018
*/
public class VariableSwapsApp {
/**
* 四则运算
* @param a
* @param b
*/
public static void method1(int a, int b) {
a = a + b;
b = a -b ;
a = a - b;
System.out.println("交换后的数字a = " + a + " b = " + b);
}
/**
* 异或运算
* @param a
* @param b
*/
public static void method2(int a, int b) {
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("交换后的数字a = " + a + " b = " + b);
}
public static void main(String[] args) {
int a = 6;
int b = 7;
System.out.println("交换前的数字a = " + a + " b = " + b);
method1(a, b);
method2(a, b);
}
}
2)测试结果
5 参考文献
[1] Robert, Lafore., Java数据结构和算法. 第2版,中国电力出版社.
[2] 何海涛, 剑指off,第1版,电子工业出版社出版