связанный список XOR

Недавно я наткнулся на ссылку ниже, которая показалась мне довольно интересной.

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

  • Инструменты отладки общего назначения не могут следовать цепочке XOR, что усложняет отладку; [1]
  • Платой за уменьшение использования памяти является увеличение сложности кода, что делает обслуживание более дорогим;
  • Большинство схем сборки мусора не работают со структурами данных, не содержащими буквенных указателей;
  • XOR указателей не определено в некоторых контекстах (например, в языке C), хотя многие языки обеспечивают некоторое преобразование типов между указателями и целыми числами;
  • Указатели будут нечитаемыми, если вы не проходите по списку — например, если указатель на элемент списка содержится в другой структуре данных;
  • При перемещении по списку вам необходимо помнить адрес ранее доступного узла, чтобы вычислить адрес следующего узла.

Теперь мне интересно, это исключительно для низкоуровневых языков или это также возможно в C#?

Есть ли аналогичные варианты для получения таких же результатов с C#?


person Guapo    schedule 12.05.2011    source источник


Ответы (7)


TL;DR Я быстро написал пробную версию реализации XorLinkedList на С#.

Это абсолютно возможно с использованием небезопасного кода на C#. Однако есть несколько ограничений:

  1. XorLinkedList должен быть «неуправляемой структурой», т. е. он не может содержать управляемые ссылки.
  2. Из-за ограничения универсальных шаблонов C# связанный список не может быть универсальным (даже с where T : struct).

Последнее, по-видимому, связано с тем, что вы не можете ограничить универсальный параметр неуправляемыми структурами. С помощью всего лишь 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;
}

Заключение

Лично я бы никогда не использовал XorLinkedList в C# (возможно, в C, когда я пишу действительно низкоуровневые системные вещи, такие как распределители памяти или структуры данных ядра. В любом другом случае небольшой выигрыш в эффективности хранения действительно не стоит боли. тот факт, что вы не можете использовать его вместе с управляемыми объектами в C#, делает его практически бесполезным для повседневного программирования.

Кроме того, хранилище сегодня почти бесплатно, даже основная память, и если вы используете C #, вы, вероятно, не слишком заботитесь о хранилище. Я где-то читал, что заголовки объектов CLR были около 40 байт, так что этот указатель будет наименьшей из ваших проблем;)

person Christian Klauser    schedule 13.05.2011
comment
Возможно, стоит отметить, что его не следует путать с оператором ^ (дескриптор объекта в управляемой куче) в C#. - person Buggieboy; 27.12.2011

C# обычно не позволяет вам манипулировать ссылками на этом уровне, так что, к сожалению, нет.

person reavowed    schedule 12.05.2011
comment
Это не совсем правильно. Структуры указателей, включая связанные списки XOR, могут быть реализованы в управляемом коде с использованием массивов и поддельных указателей, которые на самом деле являются индексами массива. - person Robin Green; 13.05.2011
comment
Не уверен, почему вы думаете, что это неудачно! - person Dexter; 13.05.2011
comment
@Robin Green - возможность имитировать что-то - это не то же самое, что быть в состоянии что-то сделать. - person reavowed; 13.05.2011
comment
там будет интересная философская дискуссия - person Robin Green; 13.05.2011

В качестве альтернативы небезопасным решениям, которые были предложены.

Если вы подкрепили свой связанный список массивом или коллекцией списков, где вместо указателя памяти «следующий» и «предыдущий» указывают индексы в массиве, вы могли бы реализовать этот xor, не прибегая к использованию небезопасных функций.

person Eric    schedule 12.05.2011

Существуют способы работы с указателями в C#, но вы можете иметь указатель на объект только временно, поэтому вы не можете использовать их в этом сценарии. Основная причина этого — сборка мусора — пока вы можете делать такие вещи, как указатели XOR и отменять их XOR позже, GC не может узнать, безопасно ли собирать определенный объект или нет.

Вы могли бы сделать что-то очень похожее, эмулируя указатели с помощью индексов в одном большом массиве, но вам пришлось бы реализовать простую форму управления памятью самостоятельно (например, при создании нового узла, где в массиве я должен его поместить?).

Другой вариант - использовать C++/CLI, который обеспечивает полную гибкость указателей, с одной стороны, и GC, а также доступ к фреймворку, когда он вам нужен, с другой.

person svick    schedule 12.05.2011

Конечно. Вам просто нужно закодировать класс. оператор XOR в С# - это ^ Это должно быть все, что вам нужно, чтобы начать кодирование. Обратите внимание, что для этого потребуется, чтобы код был объявлен «небезопасным». здесь: как использовать С#.

person soandos    schedule 12.05.2011
comment
Я не думаю, что есть какая-то просто необходимость ... в этом контексте. Вам придется возиться с небезопасным кодом и указателями, за которые C# будет бороться с вами. - person Lasse V. Karlsen; 13.05.2011
comment
Извините, редактировал сообщение, как вы прокомментировали. Да, это не так просто, но вполне возможно. - person soandos; 13.05.2011
comment
Учитывая, что вам придется обмануть компилятор, чтобы он позволил вам работать с указателями на управляемые типы, я сомневаюсь, что это будет осуществимо, а тем более применимо на любом уровне. - person Lasse V. Karlsen; 13.05.2011
comment
Почему здесь задействован обман? Я согласен, писать код как небезопасный, как правило, не очень хорошая идея, но для получения указателя на структуру требуется mystruct*, что кажется не таким уж сложным. - person soandos; 13.05.2011
comment
Я согласен, что было бы гораздо лучше написать этот класс на С++ и скомпилировать его как dll, а затем вызвать эту dll в вашей программе на С#. - person soandos; 13.05.2011
comment
Как создать новую структуру в куче и поместить указатель на нее в переменную Node*? - person Lasse V. Karlsen; 13.05.2011
comment
Вы можете получить указатель в C# только временно, используя fixed или stackalloc. Пока текущий метод завершается, закрепленный вами объект может перемещаться и, скорее всего, будет удален сборщиком мусора. - person svick; 13.05.2011

Делая здесь широкое обобщение: C#, похоже, пошел по пути удобочитаемости и чистых интерфейсов, а не по пути битовой возни и максимально плотной упаковки всей информации.

Итак, если у вас нет особой потребности здесь, вы должны использовать список, который вам предоставлен. Будущие программисты сопровождения будут вам за это благодарны.

person Andrei    schedule 12.05.2011

Это возможно, однако вы должны понимать, как С# смотрит на объекты. Переменная экземпляра фактически содержит не объект, а указатель на объект в памяти.

DateTime dt = DateTime.Now;

dt — указатель на структуру в памяти, содержащую схему DateTime.

Таким образом, вы можете сделать этот тип связанного списка, хотя я не уверен, почему вы это сделаете, поскольку структура обычно уже реализовала наиболее эффективные коллекции. В качестве эксперимента мысли это возможно.

person Bueller    schedule 12.05.2011
comment
Плохой пример: DateTimes являются структурами и, следовательно, типами значений, а не ссылочными типами. - person reavowed; 13.05.2011