目录
1.前言
2.位运算符
3.位运算符应用
前言
在我们开发程序过程中,计算机实际并不认识我们写的代码,我们平时写的代码最终都是通过编译器转换为0/1的二进制文件交给计算机执行,而位运算则是直接操作这些二进制数据,位运算是一种极为高效乃至可以说最为高效的计算方式,虽然现代程序开发中编译器已经为我们做了大量的优化,但是合理的使用位运算可以提高代码的可读性以及执行效率。 iOS也有很多场景使用到如枚举、色彩存储等。
位运算符
位运算符总共有如下四种
1.& 按位与
2.| 按位或
3.^ 按位异或
4.~ 取反
5.<< 左移
6.>> 右移
& 按位与
规律:和1相同取1,否则为0
比如:7 & 1 的值为多少?
将其转换为二进制
7: 0111
1: 0001
按照上面规则结果为:0001 为 1
所以 7 & 1 = 1
| 按位或
规律:只要有1就为1
比如:7 | 1 的值为多少?
将其转换为二进制
7: 0111
1: 0001
按照上面规则结果为:0111 为 7
所以 7 | 1 = 7
^ 按位异或
规律1:不相同为1,相同为0
比如:7 ^ 1 的值为多少?
7: 0111
1: 0001
按照上面规则结果为:0110 为 6
所以 7 ^ 1 = 6
规律2:异或的结果和参与运算的顺序没有关系
如 9 ^ 5 ^ 6 和 5 ^ 6 ^ 9 结果是一样的
9: 1001
5: 0101
-> 1100
6: 0110
结果:1010 == 10
5: 0101
6: 0110
-> 0011
9: 1001
结果:1010 == 10
规律3:相同的两个数异或等于0
如 5 ^ 5
5: 0101
5: 0101
结果:0000 == 0
规律4:任何一个数异或上0结果不变
如 5 ^ 0
5: 0101
0: 0000
结果:0101 == 5
规律5: 任何一个数异或上同一个数两次,结果不变
如 9 ^ 5 ^ 5 \
9: 1001
5: 0101
-> 1100
5: 0101
结果:1001 == 9
~ 取反
规律1:正整数的按位取反是其本身+1的负数
即 ~9 = -10
规律2:负整数的按位取反是其本身+1的绝对值
即 ~-9 = 8
规律3:零的按位取反是 -1
即 ~0 = -1
<< 左移
格式:整数<<左移个数
例子:x << n
实质:x * 2n
操作:把 x 的二进制位 向左移动 n 个单位,高位丢弃,低位补0
如: 1 << 2
1: 0001
<< 0100
结果为:4
<< 右移
格式:整数>>右移个数
例子:x >> n
实质:x / 2n (2的n次方)
操作:把 x 的二进制位 向右移动 n 个单位,低位丢弃,符号位不变
常见的枚举如:8 >> 1
8: 0100
·>> 0010
结果为:4
位运算符应用
- 在OC中我们经常看到系统一些定义枚举很多都是下图这样:
- 下面我们自己也来通过位运算实现一个枚举:
typedef enum {
OptionsNone = 0, // 0b0000
OptionsOne = 1<<0, // 0b0001
OptionsTwo = 1<<1, // 0b0010
OptionsThree = 1<<2, // 0b0100
OptionsFour = 1<<3 // 0b1000
} Options;
- (void)setOptions:(Options)options
{
if (options & OptionsOne) {
NSLog(@"包含了 OptionsOne");
}
if (options & OptionsTwo) {
NSLog(@"包含了 OptionsTwo");
}
if (options & OptionsThree) {
NSLog(@"包含了 OptionsThree");
}
if (options & OptionsFour) {
NSLog(@"包含了 OptionsFour");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
//设置一下OptionsOne 和 OptionsFour
[self setOptions: OptionsOne | OptionsFour];
//打印 : 包含了 OptionsOne , 包含了OptionsFour
}
通过上面的代码我们分析一下为什么调用 [self setOptions: OptionsOne | OptionsFour] 这个方法就会打印设置的参数;
首先我们通过上面的学习知道:OptionsOne的值是0b0001(0b表示二进制),OptionsFour的值是0b0100
所以 OptionsOne | OptionsFour 就是 0001 | 0100 结果为:0101
所以 (options & OptionsOne) = 0101 & 0001
结果为 0001 值为1(大于0,Bool值为YES),执行打印内容
所以 (options & OptionsFour) = 0101 & 0100 结果为 0100 值为4,为YES,执行打印内容
- 再看一道LeetCode上面的算法题: leetcode-cn.com/problems/si…
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
通过我们对位运算的学习,是不是就发现使用 ^ 就能很轻松解决
回顾 ^的几个规律:
异或的结果和参与运算的顺序没有关系相同的两个数异或等于0任何一个数异或上0结果不变
func singleNumber(_ nums: [Int]) -> Int {
var value = 0
for num in nums{
value = value ^ num
}
return value
}