最近,我读过一篇文章,向我展示了如何使用单个指针字段实现双向链表,即像单个链表一样。与将XOR prev和下一个地址存储在单个字段中有关。我不知道这有助于我们前后横穿?谁可以给我解释一下这个?我读过here上的文章。任何人都可以向我解释这个吗?更详细一点? XOR如何与这些地址有关。
答案 0 :(得分:6)
正如文章所指出的,只有当你在列表的头部或尾部有一个指针时,这种技术才有用。如果你只有一个指针在列表中间,那就无处可去。
关于技术:考虑以下链表:
|0|A|0x01|<->|0x01|B|0x02|<->|0x02|C|0|
该列表包含3个节点,其值A,B,C和prev / next指针包含列表中prev / next元素的十六进制值(地址)。值0为空
如果存储2个指针,我们只能使用一个,如文章中所述:
|A|0x01|<->|B|0x03|<->|C|0x03|
接下来我们将调用新字段link = prev XOR。所以记住这一点:
A.link = 0^0x01 = 0x01
B.link = 0x01^0x02 = 0x03
C.link = 0x03^0x0 = 0x03.
假设你有一个指向列表头部的指针(你知道将prev指针设置为null),这里是你如何遍历列表:
p=head;
prev = 0;
while(p.link!=prev)
{
next = p.link^prev
prev=p
p=next
}
使用相同的逻辑
在列表中向后移动答案 1 :(得分:1)
XOR有这个有趣的属性:如果给你A和C = A ^ B,你可以计算A ^ C = A ^(A ^ B)=(A ^ A)^ B = B.
对于链表,如果给出前向指针或后向指针以及两者的XOR,则可以找到具有单个XOR的另一个指针。当您迭代列表时,您已经拥有其中一个,所以您需要的只是寻找另一个的XOR;因此无需存储两者。
答案 2 :(得分:0)
据我所知,它依赖于XOR运算符的属性,比如说:
XOR A = 0
使用双向链表时,您必须在结构中保存“下一个”和“上一个”地址。 作者说,为了节省空间,你可以存储:
下一个XOR prev
通过执行以下操作浏览您的列表:
next =当前XOR prev
下一个=(下一个XOR上一个)XOR prev
next = next XOR(prev XOR prev)
但我真的不明白,因为在这个例子中你仍然需要知道“prev”才能进行计算......
答案 3 :(得分:0)
这样:
你在某个节点。你需要去下一个。但是你有一个变量需要存储两个指针的值。这怎么可能?
我们利用这样的事实:当我们遍历列表时,我们知道先前访问过的节点的节点地址。但是怎么样?
所以,问题归结为:
我们需要在一个变量中存储两个值。在任何时候,我们都知道其中任何一个。我们需要找到另一个。有可能吗?
答案是是。
v = a^b;
then v^b = a and v^a = b
现在,将此概念应用于DLL。
存储XOR of previous and next node's addresses in the current node
当您希望遍历到下一个节点时,XOR
上一个节点的地址,其值存储在当前节点中。你可以遍历下一个。同样,人们可以向后移动。
答案 4 :(得分:0)
优美的解释。这种解释使得很容易理解这个概念。
我将使其更简单然后将更有用。假设您有3个节点,即A,B和C.A中存储的地址为1(即二进制格式的01),B中的地址为2(即二进制格式的10),C中的地址为3(即二进制格式的11)。这样更清楚。
A B C
01 10 11 --->>this 01,10,11 are addresses.
现在,XOR属性显示当位相同时,我们得到0,否则得到1。
因此,当您的当前节点为B(即地址10)时,您想继续前进。
意味着您要做的是A XOR B
或01 XOR 10
,即
01
xor 10
=11 i.e by doing xor of 01 and 10 it will make you reach at 11 address that is C.
类似地,当您执行10 xor 11时,答案是01,即A。