【问题标题】:Doubly Linked List to JSON双向链表到 JSON
【发布时间】:2014-07-29 03:15:28
【问题描述】:

我有一个三维结构......实际上是一个具有六个节点的双向链表,即左、右、上、下、内、外。如果一个节点位于另一个节点的右侧,则该节点将挑衅地位于第一个节点的左侧。喜欢

实际上这是一个 3D 结构,但为了便于理解,我给出了一个 2D 示例。 现在我必须将其转换为 JSON 格式,以通过 WCF 将此数据发送到客户端,但由于它包含循环,因此无法转换为 JSON。我有这些问题

  1. 这种类型的双向链表可以转成JSON吗?
  2. 还有其他方法吗?
  3. 还有其他推荐的数据结构吗?如果这不可能使用双向链表。

我正在使用Json.Net 来处理 JSON。

我的课是

public class Node
{
    public Document document = null;

    public Node left = null;
    public Node right = null;
    public Node up = null;
    public Node down = null;
    public Node inside = null;
    public Node outside = null;
}

【问题讨论】:

  • 您可以给每个节点一个 ID 并使用它来序列化/反序列化节点:[{Id=0, Right=1}, {Id=1, Left=0}]。一个类似的选项是拥有一组节点和一组顶点(如果连接是无向的,这可能会更好)。
  • 你的意思是我应该选择图形数据结构?
  • 您已经拥有有限的图形数据结构(Node 是您的术语)。这取决于您如何表示它 - 数据是相同的数据。 (例如,您也可以使用 3D 数组并且完全没有边)
  • 没错,兄弟,你是对的,它是一个有 6 条无向边的图...... 3D 数组是我的首选,但问题是我必须从中间开始填充数据并远离角落。

标签: c# json data-structures json.net doubly-linked-list


【解决方案1】:

如果您在设置中设置PreserveReferencesHandling 选项,Json.Net 可以处理引用循环。

JsonSerializerSettings settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(rootNode, settings);

此设置将导致 JSON 写入特殊的 $id$ref 属性,允许将 JSON 反序列化回原始引用,假设您使用 Json.Net 在客户端进行反序列化。有了这个,您应该可以毫无问题地使用现有的对象结构。

演示:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

public class Program
{
    public static void Main()
    {
        Node center = new Node { Name = "In House" };
        Node north = new Node { Name = "North of House" };
        Node west = new Node { Name = "Front of House" };
        Node east = new Node { Name = "Back of House" };
        Node south = new Node { Name = "South of House" };

        center.East = east;
        east.West = center;

        center.West = west;
        west.East = center;

        east.North = north;
        north.East = east;

        east.South = south;
        south.East = east;

        south.West = west;
        west.South = south;

        west.North = north;
        north.West = west;

        DumpNodes(center);

        Console.WriteLine();

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
        settings.NullValueHandling = NullValueHandling.Ignore;
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(center, settings);
        Console.WriteLine(json);

        Node node = JsonConvert.DeserializeObject<Node>(json, settings);

        Console.WriteLine();

        DumpNodes(node);
    }

    private static void DumpNodes(Node startingNode)
    {
        HashSet<Node> seen = new HashSet<Node>();
        List<Node> queue = new List<Node>();
        queue.Add(startingNode);
        while (queue.Count > 0)
        {
            Node node = queue[0];
            queue.RemoveAt(0);
            if (!seen.Contains(node))
            {
                seen.Add(node);
                Console.WriteLine(node.Name);
                Look("north", node.North, queue, seen);
                Look("west", node.West, queue, seen);
                Look("east", node.East, queue, seen);
                Look("south", node.South, queue, seen);
            }
        }
    }

    private static void Look(string dir, Node node, List<Node> queue, HashSet<Node> seen)
    {
        if (node != null)
        {
            Console.WriteLine("   " + dir + ": " + node.Name);
            if (!seen.Contains(node))
            {
                queue.Add(node);
            }
        }
    }
}

public class Node
{
    public string Name { get; set; }
    public Node North { get; set; }
    public Node South { get; set; }
    public Node East { get; set; }
    public Node West { get; set; }
}

输出:

In House
   west: Front of House
   east: Back of House
Front of House
   north: North of House
   east: In House
   south: South of House
Back of House
   north: North of House
   west: In House
   south: South of House
North of House
   west: Front of House
   east: Back of House
South of House
   west: Front of House
   east: Back of House

{
  "$id": "1",
  "Name": "In House",
  "East": {
    "$id": "2",
    "Name": "Back of House",
    "North": {
      "$id": "3",
      "Name": "North of House",
      "East": {
        "$ref": "2"
      },
      "West": {
        "$id": "4",
        "Name": "Front of House",
        "North": {
          "$ref": "3"
        },
        "South": {
          "$id": "5",
          "Name": "South of House",
          "East": {
            "$ref": "2"
          },
          "West": {
            "$ref": "4"
          }
        },
        "East": {
          "$ref": "1"
        }
      }
    },
    "South": {
      "$ref": "5"
    },
    "West": {
      "$ref": "1"
    }
  },
  "West": {
    "$ref": "4"
  }
}

In House
   west: Front of House
   east: Back of House
Front of House
   north: North of House
   east: In House
   south: South of House
Back of House
   north: North of House
   west: In House
   south: South of House
North of House
   west: Front of House
   east: Back of House
South of House
   west: Front of House
   east: Back of House

在这里工作:https://dotnetfiddle.net/EojsFA

【讨论】:

  • 你知道它是否可以将专用 JSON 反序列化回内存中的对象并保留引用吗?
  • @Matt 是的。如果您不相信,我创建了一个working demo,它创建了一些节点,将它们与循环引用链接,转储出对象关系,将结构序列化为 JSON 并将PreserveReferencesHandling 设置为Objects,将 JSON 反序列化回对象,最后转储出反序列化结构的对象关系。可以看到确实保留了引用。
【解决方案2】:

任何 3D 数组(或任何维度的数组)本质上都是 1D 数组。你甚至可以认为所有数组都是一维数组,因为二维数组可以(逻辑上)解释为数组的数组,3D 是数组数组的数组,等等。

如果您的结构类似于立方体,那么它只是一个 3D 数组。将其存储在链接列表中并不重要。所以要做到这一点,只需抓住一个角(比如左下角),然后逐行、逐平面地遍历您的结构并将对象存储到 1D(或 3D)数组中。在另一端以相同的方式构造它。

您的序列化看起来像这样(其中 (x,y,z) 是您为每个节点拥有的任何内容)

[(0,0,0), (0,0,1), (0,0,2), (0,0,3), (0,1,0), (0,1,1), (0,1,2), (0,1,3), ...]

如果您的结构具有任意 3D 形状,则任意选择任意节点,然后将其余节点视为树结构。每个元素最多可以有 6 个子节点。因此,假设您选择“中心节​​点”,您首先要描述它有哪些子节点,然后再描述子节点的子节点(如果有的话)。给每个节点一个唯一的 ID 来区分它们。在描述该节点的子节点之前将节点描述为子节点很重要,否则您将无法在另一端构造它。

你的结构应该是这样的:

[{id=0, left=1,right=2,up=3,down=null,in=4,out=5},
{id=1, left=6, right=0, up=7, down=null, in=8, out=9},
...]

如果您愿意,您可以放心地忽略链接列表中的任何双向信息,因为第二种方式是多余的。

【讨论】:

    【解决方案3】:

    您拥有的是网络。一种表示形式是边列表。你的似乎都是双向的,所以它可能看起来像这样:

    [
        {source:"Left Node", destination:"Center Node"},
        {source:"Center Node", destination:"Up Node"},
        {source:"Center Node", destination:"Down Node"},
        {source:"Center Node", destination:"Right Node"},
        ...
    ]
    

    您可以使用网络遍历来吐出 Json。具体算法取决于您拥有的特定网络。但是在网络上搜索应该会给你所有你需要的示例代码。

    双向链表肯定不是你需要的,除非你有一个非常具体的网络,可以使用每条边按顺序遍历一次。

    另一种可能性是您实际上只是在处理体素。也就是说,您的所有节点都只是 3d 立方体中的坐标。一个体素与另一个体素相邻的事实意味着存在连接。因此,如果左节点位于 并且中心节点位于 则存在连接,因为所有坐标都相同,除了 Y 仅相差 1。存储只是一个列表现有节点。

    您的问题提到了 3D 结构,因此如果节点都位于特定距离处,则似乎存在体素表示。相反,如果距离是随机的,那么您将需要走网络路线。

    【讨论】:

    • 是的,你是对的,这些是 3D 立方体中的坐标,我必须在每次迭代中访问最近的可能节点并远离中心。 @DirkBester s26.postimg.org/o2t8kb0c9/Untitled.png
    • 好吧,那么如果您需要以这种方式访问​​,您需要实现为网络并从距离中心最近的节点开始进行广度优先遍历。
    猜你喜欢
    • 1970-01-01
    • 2015-10-12
    • 1970-01-01
    • 2013-11-15
    • 2019-06-03
    • 2015-03-24
    • 2015-04-04
    • 2021-11-18
    相关资源
    最近更新 更多