最近,我读了一篇文章,向我展示了如何仅使用一个指针字段(即,像单个链接列表)来实现双向链接列表。与将XOR上一个和下一个地址存储在单个字段中有关。我不知道这如何帮助我们前后移动?谁可以给我解释一下这个?我已经阅读了here上的文章。有人可以向我解释吗?更详细一点?以及XOR与这些地址有何关系。
正如本文所指出的,仅当您在列表的开头或结尾都有指针时,此技术才有用;如果列表中间只有一个指针,则无处可去。
关于技术:考虑以下链接列表:
|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
}
您使用相同的逻辑在列表中向后移动
[异或具有这个有趣的属性:如果给定A且C = A ^ B,则可以计算A ^ C = A ^(A ^ B)=(A ^ A)^ B = B。
对于链表,如果给定了前向指针或后向指针以及两者的XOR,则可以找到具有单个XOR的另一个指针。当您遍历列表时,您已经拥有其中一个,因此,您所需要的就是XOR查找另一个。因此无需同时存储两者。
据我所知,它依赖于XOR运算符的属性,例如:
A XOR A = 0
使用双向链接列表时,您必须在结构中保存“下一个”和“上一个”地址。作者说,要节省空间,您可以只存储:
下一个XOR上一个
并通过以下操作浏览列表:
下一个=当前XOR上一个
next =(next XOR prev)XOR prev
下一个=下一个XOR(上一个XOR上一个)
但是我并没有真正理解这一点,因为在此示例中,您仍然必须知道“上一步”才能进行计算...
以这种方式:
您在某个节点上。您需要转到下一个。但是您只有一个变量,需要存储两个指针的值。这怎么可能?
我们利用以下事实:遍历列表时,我们知道先前访问的节点的节点地址。但是如何?
所以,问题归结为:
我们需要在一个变量中存储两个值。在任何时候,我们都知道其中任何一个。我们需要找到另一个。有可能吗?
答案是是。
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
前一个节点的地址。您可以遍历下一个。同样,也可以向后移动。
尼斯的解释很好。这种解释很容易理解这个概念。
我将使其更简单然后会更有用。假设您有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或11时,答案是01,即A。