使用位运算压缩坐标 (x, y) 的技巧以及背后原理
3710
2020.01.05
2020.03.29
发布于 未知归属地
  • 把一个 int型 坐标 (x, y) 转换成一个 long long 类型 的整数,方便存储位置状态。

思路

假如题目给了很多坐标,需要保存坐标的唯一标识,从而表示坐标的状态信息。

  • 因为坐标是 int 型是 32 位的 (64位机),而 long long 类型是 64 位的。 所以可以让高的 32 保存 x的坐标,低 32 位保存 y 的坐标。

  • 在编码 (encode) 的使用,先把 x 坐标和 y 坐标转换成 long long 类型,并向左移 32 位 (左移补 0)。然后用把当前数按位或 y 坐标。得到低 32 位是 y,高 32 位是 x。

  • 在解码 (decode) 的时候,获得 y 坐标直接把编码后的数 point 强制类型转换成 int(强制类型转换直接取低 32 位)。取 x 坐标要先把 point 右移 32 位再强制类型转换获得 x 坐标。

PS:假如坐标有负数,需要在 encode 的时候需要在强转后把 y 的前 32 位置成 0,因为负数 int 强制类型转换成 long long 高 32 位会补 1(正数补 0,计算机保存的是数的补码,整数的补码跟本身一样,负数的补码要取反 +1)增加 y &= 0x00000000ffffffff; 把高 32 位置 0, 这样按位或就能保存 x 的值了。

举一个栗子:
x = 60, y = -32760 计算机补码保存如下:

x = 0000 0000 0000 0000 0000 0000 0011 1100
y = 1111 1111 1111 1111 1000 0000 0000 1000
强制类型转换成 long long 类型 64 位
x = 00000000000000000000000000000000 0000 0000 0000 0000 0000 0000 0011 1100
y = 11111111111111111111111111111111 1111 1111 1111 1111 1000 0000 0000 1000
按位与

x: 0000 0000 0000 0000 0000 0000 0011 1100 0000 0000 0000 0000 0000 0000 0000 0000 (x 右移 32 位)
y: 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1000 0000 0000 1000 (把 y 的高 32 位置成 0)

p: 0000 0000 0000 0000 0000 0000 0011 1100 1111 1111 1111 1111 1000 0000 0000 1000

p 为压缩后的坐标。

使用

encodedecode方法

encode

c++
long long encode(long long x, long long y) {
    y &= 0x00000000ffffffff;  // 若y > 0可以不写
    return x << 32 | y;
}

decode

c++
pair<int, int> decode(long long point) {
    return {(int)(point >> 32), (int)point};
}

例子

c++
// 使用例子, 把坐标放到各个容器中,以queue为例
queue<long long> q;

int x = 299, y = -40;  // (x, y) == (299, -40)
q.push(encode(x, y);  // 把坐标状态压入队列

pair<int, int> point = decode(q.front());   // 取出状态还原坐标 
// point.first == 299,   point.second == -40
评论 (6)