C #의 트리 데이터 구조


248

C #에서 트리 또는 그래프 데이터 구조를 찾고 있었지만 제공되지 않은 것 같습니다. C # 2.0을 사용한 광범위한 데이터 구조 조사에서는 그 이유에 대해 설명합니다. 이 기능을 제공하기 위해 일반적으로 사용되는 편리한 라이브러리가 있습니까? 아마도 기사에 제시된 문제를 해결하기위한 전략 패턴을 통해서 일 것입니다.

내 ArrayList를 구현하는 것처럼 내 자신의 트리를 구현하는 것이 바보 같은 느낌이 듭니다.

균형이 맞지 않는 일반 트리를 원합니다. 디렉토리 트리를 생각하십시오. C5는 근사해 보이지만 트리 구조는 노드 계층 구조를 나타내는 것보다 검색에 더 적합한 균형 잡힌 빨강-검정 트리로 구현 된 것 같습니다.


2
좀 더 극단적 인 나무 : stackoverflow.com/questions/196294/… ;-)
Tuomas Hietanen

프로젝트에 TreeView를 포함시켜 사용할 수없는 이유가 있습니까? 실제로 사용자에게 보여줄 이유가 없습니다. 물론 이것이 옵션이 아닌 경우 여러 형태의 프로젝트가 있습니다. 특별한 복잡성이 필요한 경우 항상 TreeNode 예제에서 상속하는 새 클래스를 만들 수 있습니까?
Simply G.

9
매우 간단한 트리를 위해 전체 UI 라이브러리를 가져 오는 것은 나쁜 생각이라고 생각합니다.
스템

1
동기를 부여 할 수 있습니까? 실제 하드 드라이브 공간 요구 사항이 더 이상 문제가되지 않습니까? 모양 없는? 앞에서 언급했듯이, 이것은 기존 소프트웨어가없는 특수 소프트웨어 나 다른 솔루션에 대한 솔루션이 아니라는 것을 이해할 수 있습니다. 나는 구조를 모두 무료로 얻을 수 있다면 게으른 프로그래머입니다. 그리고 기존 라이브러리에는 무료가 많이 있습니다. 많은 사람들이이 라이브러리를 사용한 사람들로부터 많은 코드를 찾을 수 있습니다.
Simply G.

1
간단한 트리 유형은 다음과 같습니다 public class Tree<T> : List<Tree<T>> { public T Value; }..
Enigmativity

답변:


155

최선의 조언은 표준 트리 데이터 구조가 없다는 것입니다. 구현할 수있는 방법이 너무 많아서 모든 기반을 하나의 솔루션으로 처리하는 것은 불가능합니다. 솔루션이 구체적 일수록 주어진 문제에 적용 할 가능성이 줄어 듭니다. 심지어 LinkedList에 짜증이납니다. 순환 링크 목록을 원한다면 어떻게해야합니까?

구현해야 할 기본 구조는 노드 모음이며 시작하기위한 몇 가지 옵션이 있습니다. 클래스 Node가 전체 솔루션의 기본 클래스라고 가정하십시오.

트리를 아래로만 탐색해야하는 경우 Node 클래스에는 하위 목록이 필요합니다.

트리를 탐색해야하는 경우 Node 클래스는 상위 노드에 대한 링크가 필요합니다.

이 두 지점의 모든 세부 사항과 구현해야하는 다른 비즈니스 논리 (자식 제한, 자식 정렬 등)를 처리하는 AddChild 메서드를 작성하십시오.


5
개인적으로 라이브러리에 추가 할 일종의 자체 균형 이진 트리를 신경 쓰지 않을 것입니다. 이것은 단순히 adjaceny 목록을 사용하는 것보다 추가 작업입니다.
jk.

8
@ jk SortedDictionary와 SortedSet은 빨강 / 검정 나무 꼭대기에 지어 졌으므로 이것을 사용하는 것이 좋습니다.
jonp

복합 패턴을보십시오 ;-) 정확히 당신이 찾고있는 것
Nicolas Voron

119
delegate void TreeVisitor<T>(T nodeData);

class NTree<T>
{
    private T data;
    private LinkedList<NTree<T>> children;

    public NTree(T data)
    {
         this.data = data;
        children = new LinkedList<NTree<T>>();
    }

    public void AddChild(T data)
    {
        children.AddFirst(new NTree<T>(data));
    }

    public NTree<T> GetChild(int i)
    {
        foreach (NTree<T> n in children)
            if (--i == 0)
                return n;
        return null;
    }

    public void Traverse(NTree<T> node, TreeVisitor<T> visitor)
    {
        visitor(node.data);
        foreach (NTree<T> kid in node.children)
            Traverse(kid, visitor);
    }
}

간단한 재귀 구현 ... <40 줄의 코드 ... 클래스 외부의 트리 루트에 대한 참조를 유지하거나 다른 클래스로 래핑해야합니다.


22
이 경우 C #에서는 자신의 대리자를 작성하지 않고 미리 만든 Action<T>대리자를 사용할 수 있습니다 public void traverse(NTree<T> node, Action<T> visitor). Action <>의 서명은 다음과 같습니다 void Action<T>( T obj ). 0 ~ 4 개의 다른 매개 변수 버전도 있습니다. 라는 함수에 대한 유사한 대의원도 있습니다 Func<>.
베니 Jobigan

2
이 대리인에게 어떻게 전화합니까?
Freakishly

3
트래버스 메소드를 정적으로 변경하거나 재귀 적 속성을 숨기도록 래핑하는 것이 좋은 생각이지만 트래버스하는 것은 간단합니다. 대리인의 서명으로 메소드를 작성하십시오. -필요한 경우 정적으로 만들고 델리게이트를 인스턴스화하십시오. TreeVisitor <int> my_visitor = my_visitor_impl; 그런 다음 루트 노드 또는 NTree 클래스를 정적 ​​상태로 만들면 NTree <int> .traverse (my_tree, my_visitor)
Aaron Gage

10
addChild ()가 추가 한 NTree를 반환하면 트리에 데이터를 추가하는 것이 더 좋습니다. (새로 추가 된 child == getChild (1)?의 구현 세부 사항에 의존하지 않고 이것으로 트리를 만드는 교활한 방법을 찾지 못한 경우
Rory

1
이 진술 --i == 0은 단일 경우에만 작동 한다고 생각 합니까? 이것이 사실입니까? 이 날 혼란스럽게 만든
와세 엠 아마드 나임에게

57

여기 내 의견 으로는 Aaron Gage 와 매우 유사한 광산이 있습니다. 내 목적으로와 관련하여 성능 문제가 발생하지 않았습니다 List<T>. 필요한 경우 LinkedList로 쉽게 전환 할 수 있습니다.


namespace Overby.Collections
{
    public class TreeNode<T>
    {
        private readonly T _value;
        private readonly List<TreeNode<T>> _children = new List<TreeNode<T>>();

        public TreeNode(T value)
        {
            _value = value;
        }

        public TreeNode<T> this[int i]
        {
            get { return _children[i]; }
        }

        public TreeNode<T> Parent { get; private set; }

        public T Value { get { return _value; } }

        public ReadOnlyCollection<TreeNode<T>> Children
        {
            get { return _children.AsReadOnly(); }
        }

        public TreeNode<T> AddChild(T value)
        {
            var node = new TreeNode<T>(value) {Parent = this};
            _children.Add(node);
            return node;
        }

        public TreeNode<T>[] AddChildren(params T[] values)
        {
            return values.Select(AddChild).ToArray();
        }

        public bool RemoveChild(TreeNode<T> node)
        {
            return _children.Remove(node);
        }

        public void Traverse(Action<T> action)
        {
            action(Value);
            foreach (var child in _children)
                child.Traverse(action);
        }

        public IEnumerable<T> Flatten()
        {
            return new[] {Value}.Concat(_children.SelectMany(x => x.Flatten()));
        }
    }
}

생성자에서 Value 속성을 설정할 때 Value 속성이 노출되는 이유는 무엇입니까? 생성자를 통해 이미 설정 한 후에 조작 할 수 있도록 열려 있습니까? 개인 세트 여야합니까?
PositiveGuy

물론, 왜 불변이되지 않습니까? 편집했습니다.
Ronnie Overby

감사! 나는 내 자신을 쓸 필요가 없었습니다. (아직 그것이 그것이 기본적으로 존재하는 것은 아니라고 믿을 수 없습니다. 나는 항상 .net 또는 최소한 .net 4.0이 모든 것을 가지고 있다고 생각했습니다 .)
neminem

3
이 솔루션이 마음에 들었습니다. 또한 삽입해야한다는 것을 알았으므로 다음 방법을 추가했습니다. public TreeNode<T> InsertChild(TreeNode<T> parent, T value) { var node = new TreeNode<T>(value) { Parent = parent }; parent._children.Add(node); return node; } var five = myTree.AddChild(5); myTree.InsertChild(five, 55);
JabberwockyDecompiler

48

또 다른 트리 구조 :

public class TreeNode<T> : IEnumerable<TreeNode<T>>
{

    public T Data { get; set; }
    public TreeNode<T> Parent { get; set; }
    public ICollection<TreeNode<T>> Children { get; set; }

    public TreeNode(T data)
    {
        this.Data = data;
        this.Children = new LinkedList<TreeNode<T>>();
    }

    public TreeNode<T> AddChild(T child)
    {
        TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
        this.Children.Add(childNode);
        return childNode;
    }

    ... // for iterator details see below link
}

샘플 사용법 :

TreeNode<string> root = new TreeNode<string>("root");
{
    TreeNode<string> node0 = root.AddChild("node0");
    TreeNode<string> node1 = root.AddChild("node1");
    TreeNode<string> node2 = root.AddChild("node2");
    {
        TreeNode<string> node20 = node2.AddChild(null);
        TreeNode<string> node21 = node2.AddChild("node21");
        {
            TreeNode<string> node210 = node21.AddChild("node210");
            TreeNode<string> node211 = node21.AddChild("node211");
        }
    }
    TreeNode<string> node3 = root.AddChild("node3");
    {
        TreeNode<string> node30 = node3.AddChild("node30");
    }
}

보너스
다음과 같은 본격적인 나무를보십시오.

  • 반복자
  • 수색
  • 자바 / C #

https://github.com/gt4dev/yet-another-tree-structure


코드 예제에서 검색을 어떻게 사용합니까? 어디 node에서 왔습니까? 검색 코드를 사용하려면 트리를 반복해야한다는 의미입니까?
배드민턴

@GrzegorzDev -1은 모든 IEnumerable<>멤버를 구현 하지 않으므로 컴파일되지 않으므로 -1 일 수 있습니다.
Uwe Keim

1
@UweKeim Good Job, 다음 번에는 실제 용도로 코드를 사용해보십시오.
szab.kel

내가 아는 유일한 문제는 IEnumerable <>을 구현할 때 기본 JsonConvert로 올바르게 직렬화되지 않는다는 것입니다.
Rakiah

22

일반적으로 우수한 C5 Generic Collection Library 에는 세트, 백 및 사전을 포함하여 여러 가지 다른 트리 기반 데이터 구조가 있습니다. 구현 세부 사항을 연구하려는 경우 소스 코드를 사용할 수 있습니다. (트리 구조를 구체적으로 사용하지는 않았지만 프로덕션 코드에서 C5 컬렉션을 사용했지만 좋은 결과를 얻었습니다.)


7
변경 사항이 있을지 모르지만 지금 당장 C5 사이트에서 PDF로 무료로 다운로드 할 수 있습니다.
Oskar

4
라이브러리를 보완하는 272 페이지 길이의 pdf가 있기 때문에 문서 부족은 더 이상 걱정할 필요가 없습니다 ... 코드 품질에 대해서는 언급 할 수 없지만 문서 품질로 판단 할 수 있습니다.
Florian Doyon

2
내가 이해 한 바에 따르면,이 C5 라이브러리에는 트리가 전혀 없지만 트리에서 파생 된 일부 데이터 구조 만 있습니다.
roim

10

http://quickgraph.codeplex.com/을 참조하십시오

QuickGraph는 .Net 2.0 이상을위한 일반 지향 / 무 방향 그래프 데이터 구조 및 알고리즘을 제공합니다. QuickGraph는 깊이 우선 시치, 호흡 우선 검색, A * 검색, 최단 경로, k 최단 경로, 최대 흐름, 최소 스패닝 트리, 최소 공통 조상 등의 알고리즘을 제공합니다. QuickGraph는 MSAGL, GLEE 및 Graphviz를 지원합니다. 그래프 렌더링, GraphML 로의 직렬화 등 ...


8

직접 작성하려면 C # 2.0 데이터 구조의 효과적인 사용법과 C #에서 데이터 구조의 구현 분석 방법에 대해 자세히 설명하는이 6 부 문서로 시작할 수 있습니다. 각 기사에는 예제와 함께 따를 수있는 샘플이 포함 된 설치 프로그램이 있습니다.

Scott Mitchell의 “C # 2.0을 사용한 광범위한 데이터 구조 검사”


7

솔루션에 약간의 확장이 있습니다.

재귀 적 일반 선언과 파생 서브 클래스를 사용하면 실제 대상에 더 집중할 수 있습니다.

그것은 일반적인 구현이 아닌 것과 다르므로 'NodeWorker'에서 'node'를 캐스트 할 필요가 없습니다.

내 예는 다음과 같습니다.

public class GenericTree<T> where T : GenericTree<T> // recursive constraint  
{
  // no specific data declaration  

  protected List<T> children;

  public GenericTree()
  {
    this.children = new List<T>();
  }

  public virtual void AddChild(T newChild)
  {
    this.children.Add(newChild);
  }

  public void Traverse(Action<int, T> visitor)
  {
    this.traverse(0, visitor);
  }

  protected virtual void traverse(int depth, Action<int, T> visitor)
  {
    visitor(depth, (T)this);
    foreach (T child in this.children)
      child.traverse(depth + 1, visitor);
  }
}

public class GenericTreeNext : GenericTree<GenericTreeNext> // concrete derivation
{
  public string Name {get; set;} // user-data example

  public GenericTreeNext(string name)
  {
    this.Name = name;
  }
}

static void Main(string[] args)  
{  
  GenericTreeNext tree = new GenericTreeNext("Main-Harry");  
  tree.AddChild(new GenericTreeNext("Main-Sub-Willy"));  
  GenericTreeNext inter = new GenericTreeNext("Main-Inter-Willy");  
  inter.AddChild(new GenericTreeNext("Inter-Sub-Tom"));  
  inter.AddChild(new GenericTreeNext("Inter-Sub-Magda"));  
  tree.AddChild(inter);  
  tree.AddChild(new GenericTreeNext("Main-Sub-Chantal"));  
  tree.Traverse(NodeWorker);  
}  

static void NodeWorker(int depth, GenericTreeNext node)  
{                                // a little one-line string-concatenation (n-times)
  Console.WriteLine("{0}{1}: {2}", String.Join("   ", new string[depth + 1]), depth, node.Name);  
}  

깊이는 무엇이며 어디에서 어떻게 얻습니까?
PositiveGuy

@ WeDoTDD.com 그의 클래스를 보면 Traverse가 루트 노드에서 시작하도록 0으로 선언 한 다음 traverse 메소드를 사용하여 각 반복에 int를 추가합니다.
Edward

특정 노드에 대해 전체 트리를 어떻게 검색 하시겠습니까?
mattpm

6

여기 내 것이 있습니다 :

class Program
{
    static void Main(string[] args)
    {
        var tree = new Tree<string>()
            .Begin("Fastfood")
                .Begin("Pizza")
                    .Add("Margherita")
                    .Add("Marinara")
                .End()
                .Begin("Burger")
                    .Add("Cheese burger")
                    .Add("Chili burger")
                    .Add("Rice burger")
                .End()
            .End();

        tree.Nodes.ForEach(p => PrintNode(p, 0));
        Console.ReadKey();
    }

    static void PrintNode<T>(TreeNode<T> node, int level)
    {
        Console.WriteLine("{0}{1}", new string(' ', level * 3), node.Value);
        level++;
        node.Children.ForEach(p => PrintNode(p, level));
    }
}

public class Tree<T>
{
    private Stack<TreeNode<T>> m_Stack = new Stack<TreeNode<T>>();

    public List<TreeNode<T>> Nodes { get; } = new List<TreeNode<T>>();

    public Tree<T> Begin(T val)
    {
        if (m_Stack.Count == 0)
        {
            var node = new TreeNode<T>(val, null);
            Nodes.Add(node);
            m_Stack.Push(node);
        }
        else
        {
            var node = m_Stack.Peek().Add(val);
            m_Stack.Push(node);
        }

        return this;
    }

    public Tree<T> Add(T val)
    {
        m_Stack.Peek().Add(val);
        return this;
    }

    public Tree<T> End()
    {
        m_Stack.Pop();
        return this;
    }
}

public class TreeNode<T>
{
    public T Value { get; }
    public TreeNode<T> Parent { get; }
    public List<TreeNode<T>> Children { get; }

    public TreeNode(T val, TreeNode<T> parent)
    {
        Value = val;
        Parent = parent;
        Children = new List<TreeNode<T>>();
    }

    public TreeNode<T> Add(T val)
    {
        var node = new TreeNode<T>(val, this);
        Children.Add(node);
        return node;
    }
}

산출:

Fastfood
   Pizza
      Margherita
      Marinara
   Burger
      Cheese burger
      Chili burger
      Rice burger

4

이 간단한 샘플을 사용해보십시오.

public class TreeNode<TValue>
{
    #region Properties
    public TValue Value { get; set; }
    public List<TreeNode<TValue>> Children { get; private set; }
    public bool HasChild { get { return Children.Any(); } }
    #endregion
    #region Constructor
    public TreeNode()
    {
        this.Children = new List<TreeNode<TValue>>();
    }
    public TreeNode(TValue value)
        : this()
    {
        this.Value = value;
    }
    #endregion
    #region Methods
    public void AddChild(TreeNode<TValue> treeNode)
    {
        Children.Add(treeNode);
    }
    public void AddChild(TValue value)
    {
        var treeNode = new TreeNode<TValue>(value);
        AddChild(treeNode);
    }
    #endregion
}

2

다른 사람들에게 도움이 될 수 있는 Node 클래스 를 만듭니다 . 이 클래스에는 다음과 같은 속성이 있습니다.

  • 어린이
  • 조상
  • 자손
  • 형제 자매
  • 노드의 레벨
  • 부모의
  • 뿌리
  • 기타.

Id 및 ParentId가있는 단순 항목 목록을 트리로 변환 할 수도 있습니다. 노드는 자식과 부모 모두에 대한 참조를 보유하므로 노드를 매우 빠르게 반복 할 수 있습니다.



2

@Berezh가 공유 한 코드를 완성했습니다.

  public class TreeNode<T> : IEnumerable<TreeNode<T>>
    {

        public T Data { get; set; }
        public TreeNode<T> Parent { get; set; }
        public ICollection<TreeNode<T>> Children { get; set; }

        public TreeNode(T data)
        {
            this.Data = data;
            this.Children = new LinkedList<TreeNode<T>>();
        }

        public TreeNode<T> AddChild(T child)
        {
            TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
            this.Children.Add(childNode);
            return childNode;
        }

        public IEnumerator<TreeNode<T>> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)GetEnumerator();
        }
    }
    public class TreeNodeEnum<T> : IEnumerator<TreeNode<T>>
    {

        int position = -1;
        public List<TreeNode<T>> Nodes { get; set; }

        public TreeNode<T> Current
        {
            get
            {
                try
                {
                    return Nodes[position];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }


        object IEnumerator.Current
        {
            get
            {
                return Current;
            }
        }


        public TreeNodeEnum(List<TreeNode<T>> nodes)
        {
            Nodes = nodes;
        }

        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            position++;
            return (position < Nodes.Count);
        }

        public void Reset()
        {
            position = -1;
        }
    }

좋은 디자인. 그러나 노드가 '하위 노드의 시퀀스'인지 확실하지 않습니다. 노드는 0 개 이상의 자식 노드를 가지므로 노드는 자식 노드 시퀀스에서 파생되지 않지만 자식 노드의 집계 (구성?)
Harald Coppoolse

2

여기 나무가 있습니다

public class Tree<T> : List<Tree<T>>
{
    public  T Data { get; private set; }

    public Tree(T data)
    {
        this.Data = data;
    }

    public Tree<T> Add(T data)
    {
        var node = new Tree<T>(data);
        this.Add(node);
        return node;
    }
}

이니셜 라이저를 사용할 수도 있습니다.

    var tree = new Tree<string>("root")
    {
        new Tree<string>("sample")
        {
            "console1"
        }
    };

1

대부분의 트리는 처리중인 데이터로 구성됩니다.

person누군가의 세부 사항을 포함 하는 클래스가 있다고 가정 parents하거나, "도메인 클래스"의 일부로 트리 구조를 가지거나, 개인 객체에 대한 링크가 포함 된 별도의 트리 클래스를 사용 하시겠습니까? 모두 받고 같은 간단한 작업에 대한 생각 grandchildren의를 person이 코드에 있어야 person 클래스, 또는의 사용자해야 person클래스는 별도의 트리 클래스에 대해 알고 있나요?

또 다른 예는 컴파일러의 구문 분석 트리입니다.

이 두 예가 모두 보여주는 것은 트리의 개념이 데이터 도메인 의 일부이며 별도의 범용 트리를 사용하면 생성되는 객체 수를 두 배 이상 늘리고 API를 다시 프로그래밍하기가 더 어렵다는 것입니다.

우리가 원하는 것은 표준 트리 클래스를 사용하지 않고도 모든 트리에 대해 다시 구현할 필요없이 표준 트리 작업을 재사용하는 방법입니다. Boost는 C ++에서 이러한 유형의 문제를 해결하려고 시도했지만 .NET에 대한 효과가 적용되는 것을 아직 보지 못했습니다.


@Puchacz, 죄송합니다 .C ++에서 15 년 동안 데이터를 사용하지 못했기 때문에 부스트와 템플릿을 살펴보십시오. 연구가 약한 후에는 이해할 수 있습니다. 파워는 학습 비용이 높습니다 !!
이안 링 로즈

1

위의 NTree 클래스를 사용하여 완전한 솔루션과 예제를 추가하고 "AddChild"메소드도 추가했습니다 ...

    public class NTree<T>
    {
        public T data;
        public LinkedList<NTree<T>> children;

        public NTree(T data)
        {
            this.data = data;
            children = new LinkedList<NTree<T>>();
        }

        public void AddChild(T data)
        {
            var node = new NTree<T>(data) { Parent = this };
            children.AddFirst(node);
        }

        public NTree<T> Parent { get; private set; }

        public NTree<T> GetChild(int i)
        {
            foreach (NTree<T> n in children)
                if (--i == 0)
                    return n;
            return null;
        }

        public void Traverse(NTree<T> node, TreeVisitor<T> visitor, string t, ref NTree<T> r)
        {
            visitor(node.data, node, t, ref r);
            foreach (NTree<T> kid in node.children)
                Traverse(kid, visitor, t, ref r);
        }
    }
    public static void DelegateMethod(KeyValuePair<string, string> data, NTree<KeyValuePair<string, string>> node, string t, ref NTree<KeyValuePair<string, string>> r)
    {
        string a = string.Empty;
        if (node.data.Key == t)
        {
            r = node;
            return;
        }
    }

사용

 NTree<KeyValuePair<string, string>> ret = null;
 tree.Traverse(tree, DelegateMethod, node["categoryId"].InnerText, ref ret);

트래버스가 정적 방법이어야합니까? 인스턴스 메소드 자체로 전달되는 것은 매우 어색한 것 같습니다
Sinaesthetic

0

다음은 BST 구현입니다.

class BST
{
    public class Node
    {
        public Node Left { get; set; }
        public object Data { get; set; }
        public Node Right { get; set; }

        public Node()
        {
            Data = null;
        }

        public Node(int Data)
        {
            this.Data = (object)Data;
        }

        public void Insert(int Data)
        {
            if (this.Data == null)
            {
                this.Data = (object)Data;
                return;
            }
            if (Data > (int)this.Data)
            {
                if (this.Right == null)
                {
                    this.Right = new Node(Data);
                }
                else
                {
                    this.Right.Insert(Data);
                }
            }
            if (Data <= (int)this.Data)
            {
                if (this.Left == null)
                {
                    this.Left = new Node(Data);
                }
                else
                {
                    this.Left.Insert(Data);
                }
            }
        }

        public void TraverseInOrder()
        {
            if(this.Left != null)
                this.Left.TraverseInOrder();
            Console.Write("{0} ", this.Data);
            if (this.Right != null)
                this.Right.TraverseInOrder();
        }
    }

    public Node Root { get; set; }
    public BST()
    {
        Root = new Node();
    }
}

0

GUI에이 트리를 표시하려는 경우 TreeViewTreeNode를 사용할 수 있습니다 . (기술적으로 TreeNode를 GUI에 넣지 않고 TreeNode를 만들 수 있다고 가정하지만 간단한 자체 TreeNode 구현보다 오버 헤드가 더 많습니다.)


-4

더 적은 메모리를 사용하는 루트 트리 데이터 구조 구현이 필요한 경우 다음과 같이 Node 클래스를 작성할 수 있습니다 (C ++ 구현).

class Node {
       Node* parent;
       int item; // depending on your needs

       Node* firstChild; //pointer to left most child of node
       Node* nextSibling; //pointer to the sibling to the right
}

12
C # 전용 질문에 C ++ 코드를 게시하는 것이 가장 좋은 아이디어는 아닙니다 (제이크). 특히 포인터가 포함되어 있습니다. C #에서 포인터가 무자비하게 사냥되고 있다는 것을 알고 있습니까? : p
ThunderGr

2
@ThunderGr 불공평합니다. C #에서 응답하는 것이 더 좋았지 만 C # 스피커에서 C ++ 포인터를 참조로 이해할 수 있습니다 (안전하지 않음). David Boike, Aaron Gage, Ronnie Overby, Grzegorz Dev, Berezh 및 Erik Nagel이 기본적으로 표현면에서 약간의 차이만으로 동일한 데이터 구조를 포기한 후 Jake는 링크 된 목록을 분해하여 한 가지 유형의 노드로 더 단순한 구조를 생성했습니다. 형제 탐색. 건설적인 답변을 다운 투표함으로써 C ++에 대한 당신의 혐오감을 표현하지 마십시오.
섞다

3
@ migle 나는 대답을 downvote하지 않았다 (또한 upvote하지 않았다). 그리고 저는 C ++을 싫어하지 않습니다. 제이크에게 왜 그리고 어떻게 자신의 답변을 향상시킬 수 있는지에 대한 제안을하지 않은 사람은 답이 다운 보트되는 것을 보았습니다. "더 나은 것"에 관한 것이 아닙니다. 질문은 C #으로 만 ​​태그됩니다. 태그 이외의 다른 언어로 답변을 게시하는 것은 권장되지 않으며 일부 사람들은 공감할 것입니다.
ThunderGr
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.