XOR链表

时间:2011-05-12 21:07:00

标签: c# linked-list unsafe xor xor-linkedlist

我最近看到了下面的链接,我发现它非常有趣。

http://en.wikipedia.org/wiki/XOR_linked_list

  • 通用调试工具 不能跟随XOR链,制作 调试比较困难; [1]
  • 内存减少的代价 用法是代码的增加 复杂性,使维护更多 昂贵;
  • 大多数垃圾收集计划都有 不能使用数据结构 不包含文字指针;
  • 指针的异或未定义 一些上下文(例如C语言), 虽然许多语言提供了一些 两种类型之间的转换 指针和整数;
  • 如果指针将无法读取 一个不是遍历列表 - 为 例如,如果指向列表的指针 item包含在另一个数据中 结构;
  • 在遍历列表时,您需要 记得的地址 以前访问过的节点 计算下一个节点的地址。

现在我想知道这是否仅适用于低级语言,或者是否也可以在C#中使用?

是否有任何类似的选项可以用C#生成相同的结果?

7 个答案:

答案 0 :(得分:6)

TL; DR 我很快在C#中写了一个概念验证XorLinkedList implementation

使用C#中的unsafe代码绝对可以实现。但是有一些限制:

  1. XorLinkedList必须是“非托管结构”,即不能包含托管引用
  2. 由于C#泛型的限制,链接列表不能是通用的(甚至不是where T : struct
  3. 后者似乎是因为您无法将通用参数限制为非托管结构。只需where T : struct,您还可以允许包含托管引用的结构。

    这意味着您的XorLinkedList只能保存原始值,如整数,指针或其他非托管结构。

    C#

    中的低级编程
    private static Node* _ptrXor(Node* a, Node* b)
    {
        return (Node*)((ulong)a ^ (ulong)b);//very fragile
    }
    

    非常脆弱,我知道。 C#指针和IntPtr不支持XOR运算符(可能是个好主意)。

    private static Node* _allocate(Node* link, int value = 0)
    {
        var node = (Node*) Marshal.AllocHGlobal(sizeof (Node));
        node->xorLink = link;
        node->value = value;
        return node;
    }
    

    之后不要忘记Marshal.FreeHGlobal这些节点(实施完整的IDisposable模式,并确保将免费电话放在if(disposing)块之外。

    private static Node* _insertMiddle(Node* first, Node* second, int value)
    {
        var node = _allocate(_ptrXor(first, second), value);
        var prev = _prev(first, second);
        first->xorLink = _ptrXor(prev, node);
        var next = _next(first, second);
        second->xorLink = _ptrXor(node, next);
        return node;
    }
    

    结论

    就个人而言,我永远不会在C#中使用XorLinkedList(当我编写内存分配器或内核数据结构等低级系统内容时,可能在C中。在任何其他设置中,存储效率的小增益实际上并不值得你不能在C#中将它与托管对象一起使用这一事实使得日常编​​程几乎没用。

    今天存储几乎是免费的,即使是主内存,如果你使用C#,你可能也不太关心存储。我已经读过某个地方CLR对象标题大约是40个字节,所以这个指针将是你最不关心的问题;)

答案 1 :(得分:1)

C#通常不允许你操纵那个级别的引用,所以不幸的是。

答案 2 :(得分:1)

作为已提出的不安全解决方案的替代方案。

如果您使用数组或列表集合备份链接列表,而不是内存指针“next”和“previous”指示数组中的索引,则可以实现此xor而无需使用不安全的功能。

答案 3 :(得分:1)

有很多方法可以在C#中使用指针,但是你可以暂时只能指向一个对象,所以在这种情况下你不能使用它们。这样做的主要原因是垃圾收集 - 只要您可以执行XOR指针之类的操作并在以后解除它们之后,GC就无法知道是否可以安全地收集某些对象。

你可以通过在一个大数组中使用索引来模拟指针来创建非常相似的东西,但是你必须自己实现一种简单的内存管理形式(即在创建新节点时,我应该把数组放在哪里?)。

另一种选择是使用C ++ / CLI,它既可以让你一方面获得指针的完全灵活性,另一方面可以让你在需要它时访问框架。

答案 4 :(得分:0)

不确定。你只需要编写类。 c#中的XOR运算符是^ 这应该是您开始编码所需的全部内容。 请注意,这将要求将代码声明为“不安全”。请参阅here:了解如何在c#中使用指针。

答案 5 :(得分:0)

在这里进行广泛的概括:C#似乎已经走了可读性和干净界面的道路,而不是在尽可能密集地填充和包装所有信息的路径。

因此,除非您在此处有特定需求,否则您应该使用您提供的列表。未来的维护程序员会感谢你。

答案 6 :(得分:-4)

然而,您可能必须了解C#如何查看对象。实例变量实际上不包含对象,而是指向内存中对象的指针。

DateTime dt = DateTime.Now;

dt是指向包含DateTime方案的内存中结构的指针。

所以你可以做这种类型的链表虽然我不确定为什么你会这样,因为框架通常已经实现了最有效的集合。作为思想的表达,它是可能的。