避免子节点出现在父级别的相同或更高级别

时间:2016-03-08 05:16:14

标签: c#

我正在构建一张地图。为此我需要为地图的每个节点分配一个级别,我需要自动生成这个级别。

目前我有节点之间的关系。 (与亲子关系一样) 在给定的示例中,总共有23个节点。

我不希望任何孩子与父母级别或父级别之上的级别相同。

我目前有两个dataTables。第一个包含节点ID,第二个包含与节点ID相对应的级别。

我如何在下面的代码中进行任何调整,以便任何孩子不会达到与其父级相同或更高级别的水平?

以下代码的输出是节点的x和y坐标。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace coordinatesGeneration
{
    class Program
    {
        internal class Node
        {
            public Node Parent { get; set; }
            private Node m_child;
            public Node Child
            {
                get { return m_child; }
                set
                {
                    m_child = value;
                    value.Parent = this;
                }
            }
            public int Id { get; set; }
            public string Title { get; set; }
        }


        internal class Program1
        {
            static void Main(string[] args)
            {
                Dictionary<int, Node> nodes = new Dictionary<int, Node>()
        {
        {0, new Node() {Id = 0, Title = "Node1"}},
        {1, new Node() {Id = 1, Title = "Node2"}},
        {2, new Node() {Id = 2, Title = "Node7"}},
        {3, new Node() {Id = 3, Title = "Node3"}},
        {4, new Node() {Id = 4, Title = "Node4"}},
        {5, new Node() {Id = 5, Title = "Node5"}},
        {6, new Node() {Id = 6, Title = "Node6"}},
        {7, new Node() {Id = 7, Title = "Node8"}},
        {8, new Node() {Id = 8, Title = "Node9"}},
        {9, new Node() {Id = 9, Title = "Node10"}},
        {10, new Node() {Id = 10, Title = "Node11"}},
        {11, new Node() {Id = 11, Title = "Node12"}},
        {12, new Node() {Id = 12, Title = "Node13"}},
        {13, new Node() {Id = 13, Title = "Node14"}},
        {14, new Node() {Id = 14, Title = "Node15"}},
        {15, new Node() {Id = 15, Title = "Node16"}},
        {16, new Node() {Id = 16, Title = "Node17"}},
        {17, new Node() {Id = 17, Title = "Node18"}},
        {18, new Node() {Id = 18, Title = "Node19"}},
        {19, new Node() {Id = 19, Title = "Node20"}},
        {20, new Node() {Id = 20, Title = "Node21"}},
        {21, new Node() {Id = 21, Title = "Node22"}},
        {22, new Node() {Id = 22, Title = "Node23"}}


    };
            nodes[0].Child = nodes[3];
            nodes[1].Child = nodes[3];
            nodes[2].Child = nodes[4];
            nodes[2].Child = nodes[5];
            nodes[3].Child = nodes[6];
            nodes[3].Child = nodes[7];
            nodes[3].Child = nodes[8];
            nodes[3].Child = nodes[9];
            nodes[6].Child = nodes[10];
            nodes[2].Child = nodes[11];
            nodes[2].Child = nodes[12];
            nodes[7].Child = nodes[13];
            nodes[8].Child = nodes[14];
            nodes[4].Child = nodes[15];
            nodes[5].Child = nodes[15];
            nodes[7].Child = nodes[15];
            nodes[12].Child = nodes[16];
            nodes[13].Child = nodes[16];
            nodes[13].Child = nodes[17];
            nodes[14].Child = nodes[18];
            nodes[8].Child = nodes[19];
            nodes[13].Child = nodes[20];
            nodes[14].Child = nodes[20];
            nodes[8].Child = nodes[21];
            nodes[15].Child = nodes[21];
            nodes[18].Child = nodes[22];
            nodes[19].Child = nodes[22];

            int parentlessNodeCounter = 0;
            Dictionary<int, List<Node>> nbParentNodesDictionary = new Dictionary<int, List<Node>>();
            foreach (KeyValuePair<int, Node> valuePair in nodes)
            {   
                Node parent = valuePair.Value.Parent;
                int nbOfParent = 0;

                if (valuePair.Value.Parent == null)
                    parentlessNodeCounter++;
                while (parent != null)
                {
                    nbOfParent++;
                    parent = parent.Parent;
                }
                if (valuePair.Value.Parent == null && parentlessNodeCounter > 1)
                    nbOfParent ++;
                if (!nbParentNodesDictionary.ContainsKey(nbOfParent))
                {
                    nbParentNodesDictionary[nbOfParent] = new List<Node>();
                }
                nbParentNodesDictionary[nbOfParent].Add(valuePair.Value);
            }

            const int yOffSet = 150;// initial value used for yOffset = 100; 

            foreach (KeyValuePair<int, List<Node>> keyValuePair in nbParentNodesDictionary)
            {
                const int xMax = 1000;// initial value used for xMax = 500; 
                int xOffset = xMax / (keyValuePair.Value.Count + 1);
                int x = 0;
                foreach (Node node in keyValuePair.Value)
                {
                    x += xOffset;
                    Console.Write("id:" + node.Id + " title:" + node.Title + " x:" + x + " y:" + yOffSet * keyValuePair.Key);
                }
            }

        }
    }
    }
}

2 个答案:

答案 0 :(得分:2)

据我所知,您想为给定节点计算level。我建议不要使用dict,因为你不需要。您可以在设置level时添加属性child计算级别。以下是我的主要修改:

   internal class Node
    {
      public Node(){
        Level = -1;
        Parents = new List<Node>();
      }
      public List<Node> Parents { get; set; }
      private Node m_child;
      public Node Child
      {
        get { return m_child; }
        set
        {
          m_child = value;
          value.Parents.Add(this);
          m_child.CalculateLevel();
        }
      }
      public int Id { get; set; }
      public string Title { get; set; }
      public int Level {get; private set;}
      public void CalculateLevel(){
        if(Parents.Count() == 0){
          this.Level = 0;
          return;
        }
        foreach (var parent in this.Parents)
        {
           parent.CalculateLevel();
        }

        this.Level = Parents.Select(p => p.Level).Max() + 1;
      }
    }

以下是完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace coordinatesGeneration
{
  class Program
  {
    internal class Node
    {
      public Node(){
        Level = -1;
        Parents = new List<Node>();
      }
      public List<Node> Parents { get; set; }
      private Node m_child;
      public Node Child
      {
        get { return m_child; }
        set
        {
          m_child = value;
          value.Parents.Add(this);
          m_child.CalculateLevel();
        }
      }
      public int Id { get; set; }
      public string Title { get; set; }
      public int Level {get; private set;}
      public void CalculateLevel(){
        if(Parents.Count() == 0){
          this.Level = 0;
          return;
        }
        foreach (var parent in this.Parents)
        {
           parent.CalculateLevel();
        }

        this.Level = Parents.Select(p => p.Level).Max() + 1;
      }
    }


    internal class Program1
    {
      static void Main(string[] args)
      {
        Node[] nodes = new Node[]
        {
          new Node() {Id = 0, Title = "Node1"},
          new Node() {Id = 1, Title = "Node2"},
          new Node() {Id = 2, Title = "Node7"},
          new Node() {Id = 3, Title = "Node3"},
          new Node() {Id = 4, Title = "Node4"},
          new Node() {Id = 5, Title = "Node5"},
          new Node() {Id = 6, Title = "Node6"},
          new Node() {Id = 7, Title = "Node8"},
          new Node() {Id = 8, Title = "Node9"},
          new Node() {Id = 9, Title = "Node10"},
          new Node() {Id = 10, Title = "Node11"},
          new Node() {Id = 11, Title = "Node12"},
          new Node() {Id = 12, Title = "Node13"},
          new Node() {Id = 13, Title = "Node14"},
          new Node() {Id = 14, Title = "Node15"},
          new Node() {Id = 15, Title = "Node16"},
          new Node() {Id = 16, Title = "Node17"},
          new Node() {Id = 17, Title = "Node18"},
          new Node() {Id = 18, Title = "Node19"},
          new Node() {Id = 19, Title = "Node20"},
          new Node() {Id = 20, Title = "Node21"},
          new Node() {Id = 21, Title = "Node22"},
          new Node() {Id = 22, Title = "Node23"}


        };
        nodes[0].Child = nodes[3];
        nodes[1].Child = nodes[3];
        nodes[2].Child = nodes[4];
        nodes[2].Child = nodes[5];
        nodes[3].Child = nodes[6];
        nodes[3].Child = nodes[7];
        nodes[3].Child = nodes[8];
        nodes[3].Child = nodes[9];
        nodes[6].Child = nodes[10];
        nodes[2].Child = nodes[11];
        nodes[2].Child = nodes[12];
        nodes[7].Child = nodes[13];
        nodes[8].Child = nodes[14];
        nodes[4].Child = nodes[15];
        nodes[5].Child = nodes[15];
        nodes[7].Child = nodes[15];
        nodes[12].Child = nodes[16];
        nodes[13].Child = nodes[16];
        nodes[13].Child = nodes[17];
        nodes[14].Child = nodes[18];
        nodes[8].Child = nodes[19];
        nodes[13].Child = nodes[20];
        nodes[14].Child = nodes[20];
        nodes[8].Child = nodes[21];
        nodes[15].Child = nodes[21];
        nodes[18].Child = nodes[22];
        nodes[19].Child = nodes[22];

        foreach(var n in nodes){
          Console.WriteLine(n.Title + " (Level: " + n.Level + ") > PARENTS: " + (n.Parents.Count() != 0 ? n.Parents.Count() + " ( " +  (n.Parents.Count() == 1 ? (n.Parents[0].Title + " @ " + n.Parents[0].Level) : n.Parents.Select(p => p.Title + " @ " + p.Level).Aggregate((c,next) => c + ", " + next))  + ")" : "Root") );
        }

      }
    }
  }
}

以上代码将产生以下输出。

enter image description here

这就是我计算level的方法。如果您还有其他需要,请告诉我们!

  

注意:我没有处理所有案件。因此,如果您尝试将null设置为子项,则会中断。

您也可以循环每个节点并在初始化后调用其CalculateLevel方法,并在设置Child时不要调用。

foreach(var n in nodes){
  n.CalculateLevel();
}

希望这有帮助!

答案 1 :(得分:1)

这是通过您的方法完成的,因此您无需更改现有代码。

public class Example
{
    public static void Main()
    {
        List<Node> nodes = new List<Node>
        {
          new Node {Id = 0, Title = "Node1"},
          new Node {Id = 1, Title = "Node2"},
          new Node {Id = 2, Title = "Node7"},
          new Node {Id = 3, Title = "Node3"},
          new Node {Id = 4, Title = "Node4"},
          new Node {Id = 5, Title = "Node5"},
          new Node {Id = 6, Title = "Node6"},
          new Node {Id = 7, Title = "Node8"},
          new Node {Id = 8, Title = "Node9"},
          new Node {Id = 9, Title = "Node10"},
          new Node {Id = 10, Title = "Node11"},
          new Node {Id = 11, Title = "Node12"},
          new Node {Id = 12, Title = "Node13"},
          new Node {Id = 13, Title = "Node14"},
          new Node {Id = 14, Title = "Node15"},
          new Node {Id = 15, Title = "Node16"},
          new Node {Id = 16, Title = "Node17"},
          new Node {Id = 17, Title = "Node18"},
          new Node {Id = 18, Title = "Node19"},
          new Node {Id = 19, Title = "Node20"},
          new Node {Id = 20, Title = "Node21"},
          new Node {Id = 21, Title = "Node22"},
          new Node {Id = 22, Title = "Node23"}
      };
        nodes[0].AddChild(nodes[3]);
        nodes[1].AddChild(nodes[3]);
        nodes[2].AddChild(nodes[4]);
        nodes[2].AddChild(nodes[5]);
        nodes[3].AddChild(nodes[6]);
        nodes[3].AddChild(nodes[7]);
        nodes[3].AddChild(nodes[8]);
        nodes[3].AddChild(nodes[9]);
        nodes[6].AddChild(nodes[10]);
        nodes[2].AddChild(nodes[11]);
        nodes[2].AddChild(nodes[12]);
        nodes[7].AddChild(nodes[13]);
        nodes[8].AddChild(nodes[14]);
        nodes[4].AddChild(nodes[15]);
        nodes[5].AddChild(nodes[15]);
        nodes[7].AddChild(nodes[15]);
        nodes[12].AddChild(nodes[16]);
        nodes[13].AddChild(nodes[16]);
        nodes[13].AddChild(nodes[17]);
        nodes[14].AddChild(nodes[18]);
        nodes[8].AddChild(nodes[19]);
        nodes[13].AddChild(nodes[20]);
        nodes[14].AddChild(nodes[20]);
        nodes[8].AddChild(nodes[21]);
        nodes[15].AddChild(nodes[21]);
        nodes[18].AddChild(nodes[22]);
        nodes[19].AddChild(nodes[22]);

        //Get all nodes by level
        //if any node does not have a parent it is by default in level 0

        var rootNodes = nodes.Where(i => i.IsRootElement);

        foreach (var rootNode in rootNodes)
        {
            PrintElementRecurcively(rootNode, null,0);
        }


        Console.ReadKey();
    }

    static void PrintElementRecurcively(Node nodeToPrint,Node parentNode,int depth)
    {                 
            System.Console.Write(string.Join("", Enumerable.Repeat("-", (depth*2))));
            System.Console.WriteLine("Node Id:{0}    Level:{1}     ParentId:{2}", nodeToPrint.Id, depth,
                nodeToPrint.Parents == null ? "Unknown" : parentNode.Id.ToString());

            if (nodeToPrint.Childs==null)
            {
                return;
            }

            foreach (var rootNode in nodeToPrint.Childs)
            {
                PrintElementRecurcively(rootNode, nodeToPrint, depth+1);
            }  
    }
}

internal class Node
{
    public List<Node> Parents { get;private set; }         
    public List<Node> Childs{get;private set;}        

    public int Id { get; set; }
    public string Title { get; set; }

    public void AddChild(Node newChild)
    {
        if (Childs == null)
        {
            Childs = new List<Node>();
        }
        Childs.Add(newChild);

        if (newChild.Parents==null)
        {
            newChild.Parents = new List<Node>();
        }
        newChild.Parents.Add(this);            
    }

    public Boolean IsRootElement
    {
        get
        {
            return Parents == null;             
        }
    }

    //public int Level
    //{
    //    get
    //    {
    //        if(Parents==null)
    //        {
    //            return 0;
    //        }

    //        //If you have multiple parents with different level
    //        //then it's impossible to assign that node a fixed level
    //        //you need to took one stategy
    //        // return Parents.Min(i => i.Level)+1;
    //        //return  Convert.ToInt32(Math.Floor(Parents.Average(i => i.Level)))+1;
    //        return Parents.Max(i => i.Level)+1;
    //    }
    //}



}