仅使用单个指针字段存储双向链接列表

问题描述 投票:7回答:5

最近,我读了一篇文章,向我展示了如何仅使用一个指针字段(即,像单个链接列表)来实现双向链接列表。与将XOR上一个和下一个地址存储在单个字段中有关。我不知道这如何帮助我们前后移动?谁可以给我解释一下这个?我已经阅读了here上的文章。有人可以向我解释吗?更详细一点?以及XOR与这些地址有何关系。

c doubly-linked-list
5个回答
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
投票

[异或具有这个有趣的属性:如果给定A且C = A ^ B,则可以计算A ^ C = A ^(A ^ B)=(A ^ A)^ B = B。

对于链表,如果给定了前​​向指针或后向指针以及两者的XOR,则可以找到具有单个XOR的另一个指针。当您遍历列表时,您已经拥有其中一个,因此,您所需要的就是XOR查找另一个。因此无需同时存储两者。


0
投票

据我所知,它依赖于XOR运算符的属性,例如:

A XOR A = 0

使用双向链接列表时,您必须在结构中保存“下一个”和“上一个”地址。作者说,要节省空间,您可以只存储:

下一个XOR上一个

并通过以下操作浏览列表:

下一个=当前XOR上一个

next =(next XOR prev)XOR prev

下一个=下一个XOR(上一个XOR上一个)

但是我并没有真正理解这一点,因为在此示例中,您仍然必须知道“上一步”才能进行计算...


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前一个节点的地址。您可以遍历下一个。同样,也可以向后移动。


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 B01 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。

© www.soinside.com 2019 - 2024. All rights reserved.