C# 数据结构设计

C# 数据结构设计,c#,data-structures,C#,Data Structures,我有一个很大的基础设施,有很多嵌套类,我正在寻找正确的设计模式 我会解释: 我有一个名为“Title”的类和一个名为Item的类 标题包含不同的项目,每个项目包含不同的数据 您可以在原理图中看到标题还包含包含更多项目的ItemList。 每个项目都可以包含项目 我正在添加一个基础设施的示意图,它看起来像一个非二叉树 我正在寻找这个对象的最佳数据结构 要求: 使用节点id和树节点,我将能够快速找到节点 良好的代码可维护性 可以从平面切换到树,也可以从树切换到平面 您的问题似乎要求提供一种快速方式

我有一个很大的基础设施,有很多嵌套类,我正在寻找正确的设计模式

我会解释: 我有一个名为“Title”的类和一个名为Item的类 标题包含不同的项目,每个项目包含不同的数据

您可以在原理图中看到标题还包含包含更多项目的ItemList。 每个项目都可以包含项目

我正在添加一个基础设施的示意图,它看起来像一个非二叉树

我正在寻找这个对象的最佳数据结构

要求:

  • 使用节点id和树节点,我将能够快速找到节点
  • 良好的代码可维护性
  • 可以从平面切换到树,也可以从树切换到平面

  • 您的问题似乎要求提供一种快速方式来访问给定ID值的节点,而不考虑层次结构。在这种情况下,您最好(正如Daniel Gabriel在评论中所建议的那样)创建一个平面列表,该列表针对“搜索”ID的平面列表进行了优化,因为您的查找操作并不关心层次结构。仅仅因为你的对象在一个树结构中,并不意味着你不能在另一个结构中索引它们。字典应该非常擅长这一点——键可以是整数(或者任何节点id),值可以引用节点对象实例。您只需记住将此结构与树结构保持同步。删除节点时从字典中删除键,添加节点时将键添加到字典中(如果结构是动态的)

    这满足了您的需求#1,可能也满足了#2(如果您在必要时将索引的同步封装在同一个类中)。对于#3,我们可能需要更多信息,但如果您保持这些结构的同步,您将始终能够访问这两种格式,而无需进行转换。应该很容易

    下面是一些示例代码,演示如何封装一个可以随时提供平面索引和树结构的结构:

    class Program
    {
      static void Main(string[] args)
      {
         Node<int, string> node1 = new Node<int, string>(1, "One");
         Node<int, string> node2 = new Node<int, string>(2, "Two");
         Node<int, string> node3 = new Node<int, string>(3, "Three");
         Node<int, string> node4 = new Node<int, string>(4, "Four");
         node2.Parent = node1;
         node3.Parent = node1;
         node4.Parent = node2;
         Console.WriteLine(node1.GetDump());
    
         Node<int, string> node5 = new Node<int, string>(5, "Five");
         // Test spliting the tree attaching it and it's subtree to another parent
         node2.Parent = node5;
         Console.WriteLine(node1.GetDump());
         Console.WriteLine(node5.GetDump());
    
         // Test re-attaching the detached parent as a child
         node1.Parent = node2;
         Console.WriteLine(node5.GetDump());
    
         // Test moving a node to another parent within the tree
         node1.Parent = node5;
         Console.WriteLine(node5.GetDump());
      }
    }
    
    /// <summary>
    /// Create a tree structure whose nodes are of type T and are indexed by ID type I
    /// </summary>
    /// <typeparam name="I">Type of the index</typeparam>
    /// <typeparam name="T">Type of the node</typeparam>
    class Node<I, T>
    {
      private Dictionary<I, Node<I, T>> rootIndex; // Shared flat index
      public I Id { get; private set; }
      public T Value { get; set; }
      private Node<I, T> parent;
      List<Node<I, T>> childNodes;
    
      public Node(I id, T value)
      {
         this.Id = id;
         this.Value = value;
         this.childNodes = new List<Node<I, T>>();
      }
    
      public string GetDump()
      {
         System.Text.StringBuilder sb = new StringBuilder();
         if (parent == null)
         {
            foreach (KeyValuePair<I, Node<I,T>> node in rootIndex)
            {
               sb.Append(string.Format("{0}:{1} ", node.Key, node.Value.Value));
            }
            sb.AppendLine();
         }
         sb.AppendLine(string.Format("ID={0}, Value={1}, ParentId={2}", Id, Value,
            (parent == null)?"(null)":parent.Id.ToString()));
         foreach (Node<I, T> child in childNodes)
         {
            string childDump = child.GetDump();
            foreach (string line in childDump.Split(new string[] {Environment.NewLine},
               StringSplitOptions.RemoveEmptyEntries))
            {
               sb.AppendLine("  " + line);
            }
         }
         return sb.ToString();
      }
    
      private void RemoveFromIndex(Dictionary<I, Node<I, T>> index)
      {
         index.Remove(Id);
         foreach(Node<I, T> node in childNodes)
            node.RemoveFromIndex(index);
      }
    
      private void ReplaceIndex(Dictionary<I, Node<I, T>> index)
      {
         rootIndex = index;
         rootIndex[Id] = this;
         foreach (Node<I, T> node in childNodes)
            node.ReplaceIndex(index);
      }
    
      public Node<I, T> Parent
      {
         get
         {
            return parent;
         }
         set
         {
            // If this node was in another tree, remove it from the other tree
            if (parent != null)
            {
               // If the tree is truly a separate tree, remove it and all nodes under
               // it from the old tree's index completely.
               if (value == null || (parent.rootIndex != value.rootIndex))
               {
                  // Split the child's index from the parent's
                  Dictionary<I, Node<I, T>> parentRootIndex = parent.rootIndex;
                  RemoveFromIndex(parentRootIndex);
                  rootIndex = new Dictionary<I, Node<I, T>>();
                  ReplaceIndex(rootIndex);
               }
    
               // Remove it from it's old parent node's child collection
               parent.childNodes.Remove(this);
            }
            // These operations only apply to a node that is not being removed
            // from the tree
            if (value != null)
            {
               // If parent does not already have an index, create one with itself listed
               if (value.rootIndex == null)
               {
                  value.rootIndex = new Dictionary<I, Node<I, T>>();
                  value.rootIndex[value.Id] = value;
               }
               // If the index for the child node is separate form that of the parent
               // node, merge them as appropriate
               if (this.rootIndex != value.rootIndex)
               {
                  // If this node has a complete index, merge the two tree indexes
                  // into the parent's index
                  if (this.rootIndex != null)
                  {
                     foreach (KeyValuePair<I, Node<I, T>> node in rootIndex)
                     {
                        if (value.rootIndex.ContainsKey(node.Key))
                           throw new InvalidOperationException(string.Format(
                             "Node Id {0} in child tree already exists in the parent",
                             node.Key));
                        value.rootIndex[node.Key] = node.Value;
                     }
                  }
                  else
                  {
                     // If this node does not have an index, it is not a tree;
                     // just add it to the parent's index.
                     if (value.rootIndex.ContainsKey(this.Id))
                        throw new InvalidOperationException(string.Format(
                        "Node Id {0} already exists in the parent's tree.", Id));
                     value.rootIndex[this.Id] = this;
                  }
               }
               // Make all nodes in a tree refer to a common root index.
               this.rootIndex = value.rootIndex;
               // Attach this node to the tree via the parent's child collection.
               value.childNodes.Add(this);
            }
            // Attach this node to the tree via this node's parent property
            // (null if removing from the tree)
            this.parent = value;
         }
      }
    
    
    }
    
    类程序
    {
    静态void Main(字符串[]参数)
    {
    节点1=新节点(1,“一”);
    节点node2=新节点(2,“两”);
    节点node3=新节点(3,“三”);
    节点node4=新节点(4,“四”);
    node2.Parent=node1;
    node3.Parent=node1;
    node4.Parent=node2;
    Console.WriteLine(node1.GetDump());
    节点5=新节点(5,“五”);
    //测试拆分将其及其子树附加到另一父树的树
    node2.Parent=node5;
    Console.WriteLine(node1.GetDump());
    Console.WriteLine(node5.GetDump());
    //测试将分离的父对象作为子对象重新连接
    node1.Parent=node2;
    Console.WriteLine(node5.GetDump());
    //测试将节点移动到树中的另一个父节点
    node1.Parent=node5;
    Console.WriteLine(node5.GetDump());
    }
    }
    /// 
    ///创建一个树结构,其节点类型为T,并由ID类型I索引
    /// 
    ///索引的类型
    ///节点的类型
    类节点
    {
    私有字典rootIndex;//共享平面索引
    公共I Id{get;private set;}
    公共T值{get;set;}
    私有节点父节点;
    列出子节点;
    公共节点(I id,T值)
    {
    这个.Id=Id;
    这个。值=值;
    this.childNodes=新列表();
    }
    公共字符串GetDump()
    {
    System.Text.StringBuilder sb=新的StringBuilder();
    如果(父项==null)
    {
    foreach(rootIndex中的KeyValuePair节点)
    {
    Append(string.Format(“{0}:{1}”、node.Key、node.Value.Value));
    }
    (某人);
    }
    sb.AppendLine(string.Format(“ID={0},Value={1},ParentId={2}”),ID,Value,
    (parent==null)?“(null)”:parent.Id.ToString());
    foreach(childNodes中的节点子节点)
    {
    字符串childDump=child.GetDump();
    foreach(childDump.Split中的字符串行(新字符串[]{Environment.NewLine}),
    StringSplitOptions.RemoveEmptyEntries)
    {
    某人加上一行(“+行);
    }
    }
    使某人返回字符串();
    }
    私有void RemoveFromIndex(字典索引)
    {
    索引。删除(Id);
    foreach(子节点中的节点)
    node.RemoveFromIndex(index);
    }
    专用索引(字典索引)
    {
    rootIndex=索引;
    rootIndex[Id]=这个;
    foreach(子节点中的节点)
    节点替换索引(index);
    }
    公共节点父节点
    {
    得到
    {
    返回父母;
    }
    设置
    {
    //如果此节点位于另一棵树中,请将其从另一棵树中删除
    如果(父项!=null)
    {
    //如果该树确实是一个单独的树,请删除它和下的所有节点
    //它完全来自于老树的索引。
    if(value==null | |(parent.rootIndex!=value.rootIndex))
    {
    //从父索引中拆分子索引
    字典parentRootIndex=parent.rootIndex;
    RemoveFromIndex(parentRootIndex);
    rootIndex=newdictionary();
    替换索引(rootIndex);
    }
    //将其从其旧父节点的子集合中删除
    parent.childNodes.Remove(此);
    }
    //这些操作仅适用于未被删除的节点
    //从树上
    if(值!=null)
    {
    //如果父级还没有索引,请创建一个索引,并将其自身列出
    if(value.rootIndex==null)
    {
    value.rootIndex=new Dictionary();
    value.rootIndex[value.Id]=值;
    }
    //如果子节点的索引与父节点的索引分开
    //节点,根据需要合并它们
    if(this.rootIndex!=value.rootIndex)
    {
    //如果此节点具有完整索引,请合并两个树索引
    //进入父级索引
    if(this.rootIndex!=null)
    {
    foreach(中的KeyValuePair节点