Cấu trúc dữ liệu cây trong C #


248

Tôi đang tìm kiếm một cấu trúc dữ liệu cây hoặc đồ thị trong C # nhưng tôi đoán không có cái nào được cung cấp. Một bài kiểm tra mở rộng về cấu trúc dữ liệu bằng C # 2.0 giải thích một chút về lý do tại sao. Có một thư viện thuận tiện thường được sử dụng để cung cấp chức năng này? Có lẽ thông qua một mô hình chiến lược để giải quyết các vấn đề được trình bày trong bài viết.

Tôi cảm thấy hơi ngớ ngẩn khi thực hiện cây của riêng mình, giống như tôi sẽ thực hiện ArrayList của riêng mình.

Tôi chỉ muốn một cây chung có thể mất cân bằng. Hãy nghĩ về một cây thư mục. C5 trông tiện lợi, nhưng cấu trúc cây của chúng dường như được triển khai dưới dạng cây đỏ đen cân bằng phù hợp với tìm kiếm hơn là đại diện cho một hệ thống phân cấp của các nút.



Có một số lý do người ta không thể bao gồm một TreeView trong dự án và sử dụng nó? Không có lý do để thực sự hiển thị nó cho người dùng. Tất nhiên có một số hình thức dự án khi đây không phải là một lựa chọn. Người ta luôn có thể tạo các lớp mới kế thừa từ ví dụ TreeNode nếu cần độ phức tạp đặc biệt?
Đơn giản là G.

9
Tôi sẽ coi đó là một ý tưởng tồi để nhập toàn bộ thư viện UI cho một cây rất đơn giản.
stimms

1
Bạn có thể thúc đẩy? Nó không giống như yêu cầu không gian ổ cứng thực tế là một vấn đề nữa? Hậu đậu? Như tôi đã đề cập trước đây, tôi có thể hiểu rằng đây không phải là một giải pháp cho một phần mềm chuyên dụng hoặc một cái gì đó mà không có giao diện người dùng hiện có. Tôi là một lập trình viên lười biếng, nếu tôi có thể có được một cấu trúc miễn phí thì tất cả đều tốt. Và một thư viện hiện có có rất nhiều miễn phí, người ta có thể tìm thấy rất nhiều mã từ những người đã sử dụng nó cho rất nhiều thứ.
Đơn giản là G.

Tôi không tranh luận, tôi chỉ muốn biết lý lẽ của bạn.
Đơn giản là G.

Câu trả lời:


155

Lời khuyên tốt nhất của tôi là không có cấu trúc dữ liệu cây tiêu chuẩn bởi vì có rất nhiều cách bạn có thể thực hiện nó đến mức không thể bao quát tất cả các cơ sở bằng một giải pháp. Một giải pháp càng cụ thể, nó càng ít có khả năng áp dụng cho bất kỳ vấn đề nào. Tôi thậm chí còn thấy khó chịu với LinkedList - nếu tôi muốn một danh sách liên kết tròn thì sao?

Cấu trúc cơ bản bạn sẽ cần triển khai sẽ là một tập hợp các nút và đây là một số tùy chọn để bạn bắt đầu. Giả sử rằng lớp Node là lớp cơ sở của toàn bộ giải pháp.

Nếu bạn chỉ cần điều hướng xuống cây, thì một lớp Node cần có Danh sách trẻ em.

Nếu bạn cần điều hướng lên cây, thì lớp Node cần một liên kết đến nút cha của nó.

Xây dựng một phương thức AddChild chăm sóc tất cả các chi tiết vụn vặt của hai điểm này và bất kỳ logic kinh doanh nào khác phải được thực hiện (giới hạn con, sắp xếp con cái, v.v.)


5
cá nhân tôi sẽ không nhớ một số loại cây nhị phân tự cân bằng sẽ được thêm vào thư viện vì đây là một số công việc bổ sung hơn là chỉ sử dụng một danh sách kề.
jk.

8
@jk Tôi tin rằng SortedDixi và Sortedset được xây dựng trên đỉnh cây đỏ / đen, vì vậy sử dụng chúng sẽ hoạt động.
jonp

Hãy xem mẫu tổng hợp ;-) Chính xác những gì bạn đang tìm kiếm
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);
    }
}

Thực hiện đệ quy đơn giản ... <40 dòng mã ... Bạn chỉ cần giữ một tham chiếu đến gốc của cây bên ngoài lớp hoặc bọc nó trong một lớp khác, có thể đổi tên thành TreeNode ??


22
Trong trường hợp này, trong C #, dù sao đi nữa, bạn có thể tránh viết đại biểu của riêng mình và sử dụng Action<T>đại biểu được tạo sẵn : public void traverse(NTree<T> node, Action<T> visitor). Chữ ký của hành động <> là : void Action<T>( T obj ). Ngoài ra còn có các phiên bản từ 0 đến 4 thông số khác nhau. Ngoài ra còn có một đại biểu tương tự cho các chức năng được gọi Func<>.
Benny Jobigan

2
Làm thế nào tôi sẽ gọi đại biểu này?
Freakishly

3
thay đổi phương thức di chuyển thành tĩnh hoặc có thể gói nó để ẩn bản chất đệ quy sẽ là một ý tưởng hay, nhưng thật đơn giản để tạo một phương thức với chữ ký của đại biểu, ví dụ như đối với một cây ints: void my_visitor_impl (int datum) - làm cho nó tĩnh nếu bạn cần, khởi tạo một lệnh hủy: TreeVisitor <int> my_visitor = my_visitor_impl; và sau đó gọi vào nút gốc hoặc lớp NTree nếu bạn làm cho nó tĩnh: NTree <int> .traverse (my_tree, my_visitor)
Aaron Gage

10
Làm cho addChild () trả về NTree mà nó đã thêm sẽ giúp nó đẹp hơn khi thêm dữ liệu vào cây. (Trừ khi tôi thiếu một cách khôn ngoan để xây dựng một cái cây bằng cái này, mà không dựa vào chi tiết thực hiện mà một đứa trẻ mới được thêm vào == getChild (1)?)
Rory

1
Tôi nghĩ rằng tuyên bố --i == 0này sẽ chỉ hoạt động trong trường hợp duy nhất? Điều này có đúng không. Điều này khiến tôi bối rối
Waseem Ahmad Naeem

57

Theo tôi, đây là của tôi, rất giống với Aaron Gage , theo cách hiểu thông thường hơn một chút. Đối với mục đích của tôi, tôi đã không gặp phải bất kỳ vấn đề hiệu suất với List<T>. Sẽ đủ dễ dàng để chuyển sang LinkedList nếu cần.


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()));
        }
    }
}

tại sao thuộc tính Giá trị của bạn bị lộ khi bạn đặt nó trong hàm tạo? để nó mở cho thao tác SAU KHI bạn đã thiết lập nó thông qua hàm tạo phải không? Có nên đặt riêng?
positiveGuy

Chắc chắn, tại sao không làm cho nó bất biến? Đã chỉnh sửa.
Ronnie Overby 30/03/13

Cảm ơn! Tôi khá thích không phải viết riêng của tôi. (Vẫn không thể tin rằng đó không phải là một thứ tồn tại nguyên bản. Tôi luôn nghĩ .net, hoặc ít nhất là .net 4.0, có tất cả mọi thứ .)
neminem

3
Tôi thích giải pháp này. Tôi cũng thấy tôi cần phải chèn, tôi đã thêm phương pháp sau để làm điều đó. 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

Một cấu trúc cây khác:

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
}

Sử dụng mẫu:

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");
    }
}

THƯỞNG
Xem cây đầy đủ với:

  • vòng lặp
  • đang tìm kiếm
  • Java / C #

https://github.com/gt4dev/yet-another-tree- cấu trúc


Làm cách nào để sử dụng tìm kiếm trong ví dụ mã của bạn? Nơi nào nodeđến từ đâu? Có nghĩa là tôi phải lặp đi lặp lại trên cây để sử dụng mã tìm kiếm?
Cầu lôngCat

@GrzegorzDev Có thể -1 vì nó không triển khai tất cả các IEnumerable<>thành viên, vì vậy nó không được biên dịch.
Uwe Keim

1
@UweKeim Công việc tốt, lần sau hãy thử sử dụng mã với các ứng dụng thực tế.
szab.kel

Vấn đề duy nhất tôi thấy là nó sẽ không được tuần tự hóa chính xác với JsonConvert cơ bản khi nó triển khai IEnumerable <>
Rakiah

22

Thư viện bộ sưu tập chung chung xuất sắc C5 có một số cấu trúc dữ liệu dựa trên cây khác nhau, bao gồm bộ, túi và từ điển. Mã nguồn có sẵn nếu bạn muốn nghiên cứu chi tiết thực hiện của họ. (Tôi đã sử dụng các bộ sưu tập C5 trong mã sản xuất với kết quả tốt, mặc dù tôi chưa sử dụng bất kỳ cấu trúc cây nào cụ thể.)


7
Không biết có thể mọi thứ đã thay đổi hay không nhưng ngay bây giờ cuốn sách có sẵn miễn phí để tải xuống dưới dạng PDF từ trang web C5.
Oskar

4
Thiếu tài liệu không còn là vấn đề đáng lo ngại vì có pdf dài 272 trang bổ sung cho thư viện ... Không thể nhận xét về chất lượng mã, nhưng đánh giá từ chất lượng tài liệu, tôi thực sự mong muốn được đào sâu vào tối nay!
Florian Doyon

2
Theo những gì tôi hiểu, thư viện C5 này hoàn toàn không có cây, mà chỉ có một số cấu trúc dữ liệu có nguồn gốc từ cây.
roim

10

Xem http://quickgraph.codeplex.com/

QuickGraph cung cấp các thuật toán và cơ sở dữ liệu đồ thị có hướng / không định hướng chung cho .Net 2.0 trở lên. QuickGraph đi kèm với các thuật toán như tìm kiếm độ sâu đầu tiên, tìm kiếm hơi thở đầu tiên, tìm kiếm A *, đường dẫn ngắn nhất, đường dẫn ngắn nhất, dòng chảy tối đa, cây bao trùm tối thiểu, tổ tiên ít phổ biến nhất, v.v ... QuickGraph hỗ trợ MSAGL, GLEE và Graphviz kết xuất đồ thị, tuần tự hóa thành GraphML, v.v ...


8

Nếu bạn muốn tự viết, bạn có thể bắt đầu với tài liệu sáu phần này chi tiết cách sử dụng hiệu quả cấu trúc dữ liệu C # 2.0 và cách phân tích việc triển khai cấu trúc dữ liệu của bạn trong C #. Mỗi bài viết có các ví dụ và trình cài đặt với các mẫu bạn có thể làm theo cùng.

Một cuộc kiểm tra mở rộng về cấu trúc dữ liệu bằng cách sử dụng C # 2.0 bởi Scott Mitchell


7

Tôi có một chút mở rộng cho các giải pháp.

Sử dụng một khai báo chung đệ quy và một lớp con phái sinh, bạn có thể tập trung tốt hơn vào mục tiêu thực tế của mình.

Lưu ý, nó khác với triển khai không chung chung, bạn không cần truyền 'nút' trong 'NodeWorker'.

Đây là ví dụ của tôi:

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);  
}  

độ sâu là gì và bạn lấy nó từ đâu?
positiveGuy

@ WeDoTDD.com nhìn vào lớp của mình, bạn thấy Traverse khai báo nó là 0 để bắt đầu tại nút gốc, sau đó sử dụng phương thức traverse thêm vào int mỗi lần lặp.
Edward

Làm thế nào bạn sẽ tìm kiếm toàn bộ cây cho một nút cụ thể?
mattpm

6

Đây là của riêng tôi:

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;
    }
}

Đầu ra:

Fastfood
   Pizza
      Margherita
      Marinara
   Burger
      Cheese burger
      Chili burger
      Rice burger

4

Hãy thử mẫu đơn giản này.

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

Tôi tạo một lớp Node có thể hữu ích cho người khác. Lớp này có các thuộc tính như:

  • Bọn trẻ
  • Tổ tiên
  • Hậu duệ
  • Anh chị em ruột
  • Cấp độ của nút
  • Cha mẹ
  • Nguồn gốc
  • Vân vân.

Ngoài ra còn có khả năng chuyển đổi một danh sách các mục bằng phẳng với Id và ParentId thành cây. Các nút giữ một tham chiếu đến cả con cái và cha mẹ, do đó làm cho các nút lặp khá nhanh.


2

Bởi vì nó không được đề cập, tôi muốn bạn thu hút sự chú ý của cơ sở mã .net hiện được phát hành: cụ thể là mã cho một SortedSetthực hiện Red-Black-Tree:

https://github.com/Microsoft/referencesource/blob/master/System/compmod/system/collections/generic/sortset.cs

Đây là, tuy nhiên, một cấu trúc cây cân bằng. Vì vậy, câu trả lời của tôi là tham chiếu nhiều hơn đến những gì tôi tin là cấu trúc cây bản địa duy nhất trong thư viện lõi .net.


2

Tôi đã hoàn thành mã mà @Berezh đã chia sẻ.

  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;
        }
    }

Thiết kế tốt. Tuy nhiên tôi không chắc nếu một nút 'là' một chuỗi của nút con của nó. Tôi sẽ xem xét các vấn đề sau: một nút 'có' 0 hoặc nhiều nút con, do đó, một nút không xuất phát từ một chuỗi các nút con, nhưng đó là một tập hợp (thành phần?) Của các nút con của nó
Harald Coppoolse

2

Đây là một cái cây

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;
    }
}

Bạn thậm chí có thể sử dụng bộ khởi tạo:

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

1

Hầu hết các cây được hình thành bởi dữ liệu bạn đang xử lý.

Giả sử bạn có một personlớp bao gồm các chi tiết của ai đó parents, bạn muốn có cấu trúc cây như một phần của lớp miền miền của bạn, hay sử dụng một lớp cây riêng biệt có chứa các liên kết đến các đối tượng cá nhân của bạn? Hãy suy nghĩ về một hoạt động đơn giản như lấy tất cả các grandchildrena person, mã này có nên trong person lớp hay người dùng của personlớp phải biết về một lớp cây riêng biệt?

Một ví dụ khác là cây phân tích cú pháp trong trình biên dịch

Điều mà cả hai ví dụ này cho thấy là khái niệm về cây là một phần của miền dữ liệu và sử dụng cây mục đích chung riêng biệt ít nhất là nhân đôi số lượng đối tượng được tạo cũng như làm cho API khó lập trình lại.

Những gì chúng ta muốn là một cách để sử dụng lại các hoạt động của cây tiêu chuẩn, mà không phải thực hiện lại chúng cho tất cả các cây, đồng thời, không phải sử dụng một lớp cây tiêu chuẩn. Boost đã cố gắng giải quyết loại vấn đề này cho C ++, nhưng tôi chưa thấy hiệu ứng nào cho .NET được điều chỉnh.


@Puchacz, xin lỗi tôi đã hết 15 năm dữ liệu trên C ++, hãy xem Boost và Mẫu, sau một vài nghiên cứu yếu bạn có thể hiểu chúng. Sức mạnh có chi phí học tập cao !!
Ian Ringrose

1

Tôi đã thêm giải pháp hoàn chỉnh và ví dụ sử dụng lớp NTree ở trên, cũng đã thêm phương thức "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;
        }
    }

sử dụng

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

Có nên đi qua có thể là một phương pháp tĩnh? Có vẻ như rất lúng túng khi một phương thức cá thể tự truyền vào chính nó
Sina

0

Đây là cách tôi thực hiện 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

Nếu bạn định hiển thị cây này trên GUI, bạn có thể sử dụng TreeViewTreeNode . (Tôi cho rằng về mặt kỹ thuật, bạn có thể tạo TreeNode mà không cần đặt nó trên GUI, nhưng nó có nhiều chi phí hơn so với triển khai TreeNode đơn giản tại nhà.)


-4

Trong trường hợp bạn cần triển khai cấu trúc dữ liệu cây gốc, sử dụng ít bộ nhớ hơn, bạn có thể viết lớp Node của mình như sau (triển khai 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
Đăng mã C ++ lên một câu hỏi dành riêng cho C # không phải là ý tưởng hay nhất, Jake. Đặc biệt là một trong đó bao gồm con trỏ. Bạn có biết rằng con trỏ đang bị săn lùng không thương tiếc trong C #, phải không? : p
ThunderGr

2
@ThunderGr đó là không công bằng. Trả lời bằng C # sẽ tốt hơn, nhưng những con trỏ C ++ đó có thể được hiểu bởi những người nói C # là tài liệu tham khảo (chúng ít an toàn hơn, ok). Sau khi David Boike, Aaron Gage, Ronnie Overby, Grzegorz Dev, Berezh và Erik Nagel, tất cả đều có cấu trúc dữ liệu giống nhau với sự khác biệt nhỏ chỉ trong biểu hiện, Jake đã phá vỡ danh sách liên kết mang lại một cấu trúc đơn giản hơn chỉ với một loại nút và anh chị em điều hướng. Đừng thể hiện sự không thích C ++ của bạn bằng cách bỏ phiếu trả lời mang tính xây dựng.
di chuyển

3
@migle Tôi không downvote câu trả lời (cũng không upvote). Và tôi không thích C ++. Tôi thấy rằng câu trả lời đã bị hạ thấp mà không có ai gợi ý cho Jake về lý do và cách anh ấy sẽ cải thiện câu trả lời của mình. Nó không phải là "tốt hơn". Câu hỏi được gắn thẻ chỉ dành cho C #. Đăng câu trả lời bằng ngôn ngữ khác ngoài thẻ không được khuyến nghị và một số người sẽ tải xuống.
ThunderGr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.