CatCoding

巧妙的 XOR Link List

2013-04-11

XOR Link List,只用一个附加的变量来实现双向链表。首先 xor 本身是个稍微有点难理解的操作。xor 有下面的一些特性:

A ^ 0 = A

A ^ A = 0

A ^ B = B ^ A

(A ^ B) ^ A = B

(B ^ A) ^ B = A

注意最后两条,这是 XOR Link List 的关键,这也是通过 xor 操作来实现 swap 的关键。

void xorSwap (int *x, int *y) {
     if (x != y) {
         *x ^= *y;
         *y ^= *x;
         *x ^= *y;
     }
 }

这里注意需要判断 x!=y,否则如果传入的是相同的指针,最后所指向的变量被设置为 0 了。

通过最后两条联想到双向链表中的两个指针的实现,一般如下图所示:

...  A       B         C         D         E  ...>  next –>  next  –>  next  –>
         <–  prev <–  prev  <–  prev  <

如果把 next 和 prev 用一个变量替换还能实现前向和后向遍历,那就节省了一个变量的空间。

...  A        B         C         D         E  ...
        <>  A⊕C  <->  B⊕D  <->  C⊕E  <->

比如当前在 B 节点,其 pointer 变量为 A⊕C,如果前面的 A 地址保存下来然后做运算 (A⊕C)⊕A -> C,这样就得到下一个节点指针,反向遍历同样如此。当然其缺点是逻辑复杂了,删除其中的某一个节点也不方便 (删除头和尾要好点),遍历的时候需要保存上一个节点。这样看来为了省一点点空间这样实现似乎有点不值,在大部分情况下这样的一个 pointer 的节省并没什么用,不过这其中的细节有趣、巧妙。

同样上面的 xorSwap对于现代的 CPU 来说也没什么优化,这样的代码只是更加不便于编译器来实现指令级别的优化。这种类型 trick 的东西还是要避免使用才好。

自己稍微写了一下,代码在这个 Gist

公号同步更新,欢迎关注👻