【问题标题】:Doubly-linked list serialization and deserialization on C#. How to improve codeC# 上的双向链表序列化和反序列化。如何改进代码
【发布时间】:2021-01-26 08:14:50
【问题描述】:

任务是编写双向链表的序列化和反序列化函数(不使用第三方库和标准序列化工具),以这种形式呈现:

class ListNode
{
    public ListNode Previous;
    public ListNode Next;
    public ListNode Random;
    public string Data;
}


class ListRandom
{
    public ListNode Head;
    public ListNode Tail;
    public int Count;
}

其中public ListNode Random 是对列表中随机项的引用。

我原来的解决方案是这样的:

class ListRandom
{
    public ListNode Head;
    public ListNode Tail;
    public int Count;

    private ListNode GetNodeAt(int index)
    {
        int counter = 0;
        for (ListNode currentNode = Head; currentNode.Next != null; currentNode = currentNode.Next)
        {   if (counter == index)
                return currentNode;
            counter++;
        }
        return new ListNode();
    }


    public void Serialize(Stream s)
    {
        Dictionary<ListNode, int> dictionary = new Dictionary<ListNode, int>();
        int id = 0;
        for (ListNode currentNode = Head; currentNode != null; currentNode = currentNode.Next)
        {
            dictionary.Add(currentNode, id);
            id++;
        }
        using (BinaryWriter writer = new BinaryWriter(s))
        {
            for (ListNode currentNode = Head; currentNode != null; currentNode = currentNode.Next)
            {
                writer.Write(currentNode.Data);
                writer.Write(dictionary[currentNode.Random]);
            }
        }
        Console.WriteLine("List serialized");

    }

    public void Deserialize(Stream s)
    {
        Dictionary<int, Tuple<String,int>> dictionary = new Dictionary<int, Tuple<String, int>>();
        int counter = 0;
        using (BinaryReader reader = new BinaryReader(s))
        {
            while (reader.PeekChar() != -1)
            {
                String data = reader.ReadString();
                int randomId = reader.ReadInt32();
                dictionary.Add(counter, new Tuple<String, int>( data, randomId));
                counter++;
            }
            Console.WriteLine("File readed");
        }
        Count = counter;
        Head = new ListNode();
        ListNode current = Head;
        for (int i = 0; i < Count; i++)
        {
            current.Data = dictionary.ElementAt(i).Value.Item1;
            current.Next = new ListNode();
            if (i != this.Count - 1)
            {
                current.Next.Previous = current;
                current = current.Next;
            }
            else
            {
                Tail = current;
            }
        }
        counter = 0;
        for (ListNode currentNode = Head; currentNode.Next != null; currentNode = currentNode.Next)
        {
            currentNode.Random = GetNodeAt(dictionary.ElementAt(counter).Value.Item2);
            counter++;
        }
        Console.WriteLine("List deserialized");
    }

算法如下 - 序列化时,首先我遍历列表,并从列表的一个元素和一个数字创建一个字典,它将描述该元素在列表中的索引。接下来,我正在编写到节点的文件数据,以及 ListNode Random 引用的列表项的编号。 反序列化时,我从一个数字(列表的未来元素的索引)和一对 String(元素的数据)和 int(ListNode Random 将引用的列表元素的索引)创建一个字典。接下来,我正在创建列表本身,用数据填充它,但没有为 ListNode Random 分配任何值,因为它可以引用目前不存在的元素。并在最后一个循环中,为每个 ListNode Random 分配所需的链接到列表项。

如何改进此代码/算法?

【问题讨论】:

    标签: c# serialization deserialization doubly-linked-list


    【解决方案1】:

    最简单的选择是将您的链接列表转换为像列表这样的常规集合。像 json 和 protobuf 这样的序列化格式只是有一个集合类型,即一个项目序列。未指定应如何存储,即数组/列表/链接列表。如果不需要保留 Random 节点,您可以在列表反序列化后简单地将其重新分配给任何随机节点。一个类用于序列化,另一个类用于运行时使用通常很有用,这将允许您在格式之间进行转换。

    使问题复杂化的是您的Random 节点。如果这需要保留,您不是在序列化一个简单的双向链表,而是一个图形。在这种情况下,您将需要以某种方式处理引用,可能通过为每个节点分配 id。您这样做的方式似乎合理,可能会进行调整,但总体方法看起来是合理的。

    不过,我会认真考虑使用序列化框架。我用过Protobuf.net 和这个does support references/object cycles。如果其他库具有类似的功能,我不会感到惊讶,但我没有使用它们。在大多数情况下,序列化框架会减少代码量并提高运行时性能和灵活性,因此除非您有特殊需要,否则它们将是我的首选解决方案。

    【讨论】:

    • 我完全同意你关于使用已经存在的框架并转换为常规列表,但我不能使用它们,我需要保留随机节点。问题是,这项任务是对工作的考验。不幸的是,他们说,我的解决方案不好,没有说明我的代码有什么问题。而且这个问题真的很困扰我,所以我想知道如何改进这个解决方案。
    • @luckydemon 最好的选择是问他们。我认为在拒绝某人的代码时提供解释是一种职业礼貌。您也可以考虑在 codereview.stackexchange 上发帖。如果我查看了代码,我可能会评论 Tuple 而不是 ValueTuple、ElementAt(i) 而不是常规索引器等的用法。这也可能取决于经验水平。初级和高级开发人员的标准可能完全不同。
    猜你喜欢
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多