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

时间:2014-02-03 13:17:09

标签: c doubly-linked-list

最近,我读过一篇文章,向我展示了如何使用单个指针字段实现双向链表,即像单个链表一样。与将XOR prev和下一个地址存储在单个字段中有关。我不知道这有助于我们前后横穿?谁可以给我解释一下这个?我读过here上的文章。任何人都可以向我解释这个吗?更详细一点? XOR如何与这些地址有关。

5 个答案:

答案 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 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 xor 11时,答案是01,即A。