问题:
如何只用一个指针节点实现双向链表?
英语能力有限,翻译起来不会很准确,因此在这里先做一下这篇文章的核心思想阐述:
使用一个指针,通过异或保存上一个节点的地址以及下一个节点的地址。
比如:
2^3 = 1; // 保存 1,就是本文中 ptrdiff 保存的值
2^3^2 = 3; // 异或 2 之后可以得到 3
假设现在有三个节点 prev, current, next
current->ptrdiff =(Node*) prev ^ next;
这样我们就通通过一个节点保存了另个地址,现在如何拿到前一个节点?显然
Node *tmp = (Node*)current->ptrdiff ^ next;
对于小型设备来说,每一小块内存都弥足珍贵。设备制造商需要考虑如何节省内存的使用。一种办法是,为日常使用的抽象数据结构寻找另一种实现。例如双向指针链表。
在本文中,我会用传统的方法和另一种替代方法来实现双指针链表,该双指针链表会有插入、遍历和删除操作。同时,我会打印出内存和时间使用情况,以供参考。这种替代实现的方法是基于指针距离(pointer distance),因此在本文中,我们称为指针距离实现(the pointer distance implementation)。每一个节点只需要一个指针域,就能实现向前或者向后遍历。在传统的实现中,我们需要一个指针指向前一个节点,以及另一个指针指向后一个节点。传统的节点的内存利用率只有34%,而指针距离实现的节点内存利用率是50%。如果我们使用多维的双向指针链表,比如动态网格,节点内存利用率还会更低。
在这里,我们不会讨论过多的去讨论传统的双向指针链表实现,你随便谷歌一下,会有很多相关文章。
节点定义:
typedef int T;
typedef struct listNode{
T elm;
struct listNode * ptrdiff;
};
ptrdiff
存着当前这个节点和下一个节点的差别(difference)以及当前这个节点和前一个节点的差别(difference)。指针区别是通过 异或 运算得到的。任何这种链表实例,都一个StartNode
和一个EndNode
。Start