Простой шаблон класса дерева на C#
Консольное приложение "решёток", показывающее, что при реализации "древовидного" шаблона средствами
хоть STL, хоть встроенных в .NET System.Collections
, "само дерево"-то и не нужно, достаточно реализации функциональности узла TreeNode
.
Эту реализацию, собственно, и показывает файл TreeNode.cs
, а
ExampleOfMain.cs
содержит примеры формирования дерева, обхода с выводом в консоль (отступы соблюдаются), поиска и удаления узла.
Ниже приводятся исходники файлов и проект, проверенный в актуальной сборке Visual Studio 2019.
Файл TreeNode.cs
using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace CSharpTree { 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 Boolean IsRoot { //Это корень? get { return Parent == null; } } public Boolean IsLeaf { //Это лист? get { return Children.Count == 0; } } public int Level { //Уровень в дереве? get { if (this.IsRoot) return 0; return Parent.Level + 1; } } public TreeNode(T data) { //Конструктор this.Data = data; this.Children = new LinkedList<TreeNode<T>>(); this.ElementsIndex = new LinkedList<TreeNode<T>>(); this.ElementsIndex.Add(this); } public TreeNode<T> AddChild (T child) { //Добавить потомка TreeNode<T> childNode = new TreeNode<T> (child) { Parent = this }; this.Children.Add(childNode); this.RegisterChildForSearch(childNode); return childNode; } public bool RemoveChild (TreeNode<T> childNode) { //Удалить потомка bool result = this.Children.Remove (childNode); this.UnRegisterChildForSearch (childNode); return result; } public override string ToString() { //Преобразовать в строку return Data != null ? Data.ToString() : "[data null]"; } #region searching //Просто дополнительная обёртка-сворачивалка, методы для поиска private ICollection<TreeNode<T>> ElementsIndex { get; set; } private void RegisterChildForSearch(TreeNode<T> node) { ElementsIndex.Add(node); if (Parent != null) Parent.RegisterChildForSearch(node); } private void UnRegisterChildForSearch (TreeNode<T> node) { ElementsIndex.Remove (node); if (Parent != null) Parent.UnRegisterChildForSearch (node); } public TreeNode<T> FindTreeNode(Func<TreeNode<T>, bool> predicate) { return this.ElementsIndex.FirstOrDefault(predicate); } #endregion #region iterating //Ещё один регион, переборщик IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerator<TreeNode<T>> GetEnumerator() { yield return this; foreach (var directChild in this.Children) { foreach (var anyChild in directChild) yield return anyChild; } } #endregion } }
Файл ExampleOfMain.cs
using System; using System.Text; namespace CSharpTree { class ExampleOfMain { static void Main (string [] args) { //Добавить узлы, для наглядности - дополнительные операторные скобки 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"); } } //Показать обход ShowTree (root); //Показать поиск string nameForSearch = "210"; Console.WriteLine ("Search for: " + nameForSearch); TreeNode<string> found = root.FindTreeNode (node => node.Data != null && node.Data.Contains (nameForSearch)); Console.WriteLine ("Found: " + found); //Показать удаление string nameForDeleting = "node2"; Console.WriteLine ("Deleing item "+ nameForDeleting); TreeNode <string> deleted = root.FindTreeNode (node => node.Data != null && node.Data == nameForDeleting); if (deleted != default && !deleted.IsRoot) { deleted.Parent.RemoveChild (deleted); Console.WriteLine ("Tree after deleting"); ShowTree (root); } else Console.WriteLine ("Can't delete item " + nameForDeleting); Console.ReadKey (); } private static void ShowTree (TreeNode<string> root) { //Служебный метод для обхода дерева foreach (TreeNode<string> node in root) { string indent = CreateIndent (node.Level); Console.WriteLine (indent + ( node.Data ?? "null" )); } } private static String CreateIndent (int depth) { //Служебный метод для создания отступа при выводе в консоль StringBuilder sb = new StringBuilder (); for (int i = 0; i < depth; i++) sb.Append (' '); return sb.ToString (); } } }
Скачать это решение Visual Studio в архиве .zip (5 Кб)
27.02.2021, 17:54 [1492 просмотра]