Structure des données arborescentes en C #


248

Je cherchais une structure de données arborescente ou graphique en C # mais je suppose qu'il n'y en a pas une fournie. Un examen approfondi des structures de données à l'aide de C # 2.0 explique un peu pourquoi. Existe-t-il une bibliothèque pratique couramment utilisée pour fournir cette fonctionnalité? Peut-être grâce à un modèle de stratégie pour résoudre les problèmes présentés dans l'article.

Je me sens un peu idiot d'implémenter mon propre arbre, tout comme j'implémenterais ma propre ArrayList.

Je veux juste un arbre générique qui peut être déséquilibré. Pensez à une arborescence de répertoires. C5 semble astucieux, mais leurs structures arborescentes semblent être mises en œuvre comme des arbres rouges-noirs équilibrés mieux adaptés à la recherche qu'à la représentation d'une hiérarchie de nœuds.


2
Un peu plus d'arbres extrêmes: stackoverflow.com/questions/196294/… ;-)
Tuomas Hietanen

Y a-t-il une raison pour laquelle on ne peut pas inclure un TreeView dans le projet et l'utiliser? Il n'y a aucune raison de le montrer réellement à un utilisateur. Bien sûr, il existe plusieurs formes de projets lorsque ce n'est pas une option. On peut toujours créer de nouvelles classes qui héritent de l'exemple TreeNode si une complexité particulière est nécessaire?
Simply G.

9
Je considérerais que c'est une mauvaise idée d'importer une bibliothèque d'interface utilisateur entière pour un arbre très simple.
stimule

1
Pourriez-vous motiver? Ce n'est plus comme les besoins réels d'espace disque dur est un problème? Maladroit? Comme je l'ai mentionné précédemment, je peux comprendre que ce n'est pas une solution pour un logiciel spécialisé ou quelque chose sans interface utilisateur existante. Je suis un programmeur paresseux, si je peux obtenir une structure gratuitement, c'est très bien. Et une bibliothèque existante en a beaucoup gratuitement, on peut trouver beaucoup de code de personnes qui l'ont utilisé pour beaucoup de choses.
Simply G.

Je ne discute pas, je veux juste connaître votre raisonnement.
Simply G.

Réponses:


155

Mon meilleur conseil serait qu'il n'y ait pas de structure de données arborescente standard car il y a tellement de façons de l'implémenter qu'il serait impossible de couvrir toutes les bases avec une seule solution. Plus une solution est spécifique, moins elle est applicable à un problème donné. Je m'énerve même avec LinkedList - et si je veux une liste chaînée circulaire?

La structure de base que vous devrez implémenter sera une collection de nœuds, et voici quelques options pour vous aider à démarrer. Supposons que la classe Node est la classe de base de la solution entière.

Si vous avez uniquement besoin de naviguer dans l'arborescence, une classe Node a besoin d'une liste d'enfants.

Si vous devez naviguer dans l'arborescence, la classe Node a besoin d'un lien vers son nœud parent.

Construisez une méthode AddChild qui prend en charge toutes les minuties de ces deux points et toute autre logique métier qui doit être implémentée (limites enfants, tri des enfants, etc.)


5
Personnellement, cela ne me dérangerait pas qu'une sorte d'arbre binaire auto-équilibré soit ajouté à la bibliothèque car c'est un travail supplémentaire que d'utiliser simplement une liste adjacente.
jk.

8
@jk Je crois que SortedDictionary et SortedSet sont construits au sommet d'arbres rouges / noirs, donc leur utilisation devrait fonctionner.
jonp

Jetez un œil au motif composite ;-) Exactement ce que vous cherchez
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);
    }
}

Implémentation récursive simple ... <40 lignes de code ... Vous avez juste besoin de garder une référence à la racine de l'arbre en dehors de la classe, ou de l'envelopper dans une autre classe, peut-être renommer TreeNode ??


22
Dans ce cas, en C # de toute façon, vous pouvez éviter d' écrire votre propre délégué et utiliser le fait pré- Action<T>délégué: public void traverse(NTree<T> node, Action<T> visitor). L' action de la signature <> est: void Action<T>( T obj ). Il existe également des versions de 0 à 4 paramètres différents. Il existe également un délégué analogue pour les fonctions appelées Func<>.
Benny Jobigan

2
comment pourrais-je appeler ce délégué?
Freakishly

3
changer la méthode de cheminement pour qu'elle soit statique ou éventuellement l'envelopper pour cacher la nature récursive serait une bonne idée, mais c'est simple à traverser: créez une méthode avec la signature de délégué c'est-à-dire pour un arbre de caractères: void my_visitor_impl (int datum) - le rendre statique si vous en avez besoin, instancier une delgate: TreeVisitor <int> my_visitor = my_visitor_impl; puis invoquer sur le nœud racine ou la classe NTree si vous le rendez statique: NTree <int> .traverse (my_tree, my_visitor)
Aaron Gage

10
Faire addChild () retourner le NTree qu'il a ajouté le rendrait plus agréable pour ajouter des données à un arbre. (À moins que je manque une façon astucieuse de construire un arbre avec cela, sans compter sur les détails d'implémentation qu'un enfant nouvellement ajouté == getChild (1)?)
Rory

1
Je pense que cette déclaration --i == 0ne fonctionnera qu'en cas unique? Est-ce vrai. Cela m'a rendu confus
Waseem Ahmad Naeem

57

Voici le mien, qui est très similaire à celui d' Aaron Gage , un peu plus conventionnel à mon avis. Pour mes besoins, je n'ai rencontré aucun problème de performance avec List<T>. Il serait assez facile de passer à une LinkedList si nécessaire.


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

Pourquoi votre propriété Value est-elle exposée lorsque vous la définissez dans le constructeur? qui le laisse ouvert à la manipulation APRÈS que vous l'ayez déjà défini via le constructeur, non? Devrait être un ensemble privé?
PositiveGuy

Bien sûr, pourquoi ne pas le rendre immuable? Édité.
Ronnie Overby

Merci! J'ai bien aimé ne pas avoir à écrire le mien. (Je n'arrive toujours pas à croire que ce n'est pas une chose qui existe nativement. J'ai toujours pensé que .net, ou du moins .net 4.0, avait tout .)
neminem

3
J'ai aimé cette solution. J'ai également constaté que je devais insérer, j'ai ajouté la méthode suivante pour le faire. 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

Encore une autre structure arborescente:

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
}

Exemple d'utilisation:

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

BONUS
Voir l'arbre à part entière avec:

  • itérateur
  • recherche
  • Java / C #

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


Comment utiliser la recherche dans votre exemple de code? D'où nodevient-il? Cela signifie-t-il que je dois parcourir l’arbre pour utiliser le code de recherche?
BadmintonCat du

@GrzegorzDev Peut-être -1 car il n'implémente pas tous les IEnumerable<>membres, donc il ne compile pas.
Uwe Keim

1
@UweKeim Good Job, la prochaine fois, essayez d'utiliser le code avec les utilisations réelles.
szab.kel

le seul problème que je vois est qu'il ne sera pas correctement sérialisé avec JsonConvert de base car il implémente IEnumerable <>
Rakiah

22

La bibliothèque de collections génériques C5, généralement excellente, possède plusieurs structures de données arborescentes différentes, y compris des ensembles, des sacs et des dictionnaires. Le code source est disponible si vous souhaitez étudier leurs détails d'implémentation. (J'ai utilisé des collections C5 dans le code de production avec de bons résultats, même si je n'ai utilisé aucune des arborescences spécifiquement.)


7
Je ne sais pas si les choses ont peut-être changé, mais en ce moment, le livre est disponible gratuitement en téléchargement au format PDF sur le site C5.
Oskar

4
Le manque de documentation n'est plus un problème car il y a un pdf de 272 pages qui complète la bibliothèque ... Je ne peux pas commenter la qualité du code, mais à en juger par la qualité du document, j'ai vraiment hâte de creuser ce sujet ce soir!
Florian Doyon, du

2
D'après ce que je comprends, cette bibliothèque C5 n'a pas d'arbres du tout, mais seulement quelques structures de données dérivées d'arbres.
roim

10

Voir http://quickgraph.codeplex.com/

QuickGraph fournit des infrastructures de données et des algorithmes génériques de graphes dirigés / non dirigés pour .Net 2.0 et versions ultérieures. QuickGraph est livré avec des algorithmes tels que la profondeur de la première recherche, la recherche du premier souffle, la recherche A *, le chemin le plus court, le chemin le plus court k, le débit maximal, l'arbre minimal, les ancêtres les moins courants, etc. QuickGraph prend en charge MSAGL, GLEE et Graphviz pour rendre les graphes, la sérialisation en GraphML, etc ...


8

Si vous souhaitez écrire le vôtre, vous pouvez commencer par ce document en six parties détaillant l'utilisation efficace des structures de données C # 2.0 et comment analyser votre implémentation des structures de données en C #. Chaque article contient des exemples et un programme d'installation avec des exemples que vous pouvez suivre.

«Un examen approfondi des structures de données à l'aide de C # 2.0» par Scott Mitchell


7

J'ai une petite extension aux solutions.

En utilisant une déclaration générique récursive et une sous-classe dérivée, vous pouvez mieux vous concentrer sur votre cible réelle.

Remarquez, c'est différent d'une implémentation non générique, vous n'avez pas besoin de transtyper 'node' dans 'NodeWorker'.

Voici mon exemple:

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

quelle est la profondeur et où et comment l'obtenir?
PositiveGuy

@ WeDoTDD.com en regardant sa classe, vous voyez Traverse le déclare comme 0 pour commencer au nœud racine, puis utilise la méthode traverse en ajoutant à cette int à chaque itération.
Edward

Comment rechercheriez-vous dans tout l'arbre un nœud particulier?
mattpm

6

Voici le mien:

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

Production:

Fastfood
   Pizza
      Margherita
      Marinara
   Burger
      Cheese burger
      Chili burger
      Rice burger

4

Essayez cet exemple simple.

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

Je crée une classe Node qui pourrait être utile pour d'autres personnes. La classe a des propriétés comme:

  • Les enfants
  • Les ancêtres
  • Descendance
  • Fratrie
  • Niveau du nœud
  • Parent
  • Racine
  • Etc.

Il y a aussi la possibilité de convertir une liste plate d'éléments avec un Id et un ParentId en arbre. Les nœuds contiennent une référence à la fois aux enfants et au parent, ce qui rend l'itération des nœuds assez rapide.


2

Parce qu'il n'est pas mentionné, je voudrais que vous attiriez l'attention sur la base de code .net maintenant publiée: spécifiquement le code pour un SortedSet qui implémente un Red-Black-Tree:

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

Il s'agit cependant d'une structure arborescente équilibrée. Donc ma réponse est plus une référence à ce que je crois être la seule arborescence native de la bibliothèque de base .net.


2

J'ai complété le code que @Berezh a partagé.

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

Bon design. Cependant, je ne sais pas si un nœud «est» une séquence de son nœud enfant. Je considérerais ce qui suit: un nœud 'a' zéro ou plusieurs nœuds enfants, donc un nœud n'est pas dérivé d'une séquence de nœuds enfants, mais c'est une agrégation (composition?) De ses nœuds enfants
Harald Coppoolse

2

Voici un arbre

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

Vous pouvez même utiliser des initialiseurs:

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

1

La plupart des arbres sont formés par les données que vous traitez.

Supposons que vous ayez une personclasse qui inclut les détails de quelqu'un parents, préféreriez-vous que la structure arborescente fasse partie de votre «classe de domaine», ou utilisez une classe arborescente distincte contenant des liens vers vos objets personne? Pensez à une opération simple comme obtenir tous les éléments grandchildrend'un person, ce code doit-il être dans la person classe, ou l'utilisateur de la personclasse doit-il connaître une classe d'arborescence distincte?

Un autre exemple est un arbre d'analyse dans un compilateur…

Ce que ces deux exemples montrent, c'est que le concept d'arbre fait partie du domaine des données et que l'utilisation d'une arborescence à usage général distincte au moins double le nombre d'objets qui sont créés et rend l'API plus difficile à programmer à nouveau.

Ce que nous voulons, c'est un moyen de réutiliser les opérations d'arbre standard, sans avoir à les réimplémenter pour tous les arbres, tout en n'ayant pas à utiliser une classe d'arbre standard. Boost a essayé de résoudre ce type de problème pour C ++, mais je n'ai encore vu aucun effet pour .NET s'adapter.


@Puchacz, désolé, j'ai 15 ans de données sur C ++, jetez un œil à Boost and Templates, après quelques faibles études, vous pouvez les comprendre. La puissance a des coûts d'apprentissage élevés !!
Ian Ringrose

1

J'ai ajouté une solution complète et un exemple en utilisant la classe NTree ci-dessus, j'ai également ajouté la méthode "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;
        }
    }

en utilisant

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

La traversée devrait-elle être une méthode statique? Cela semble très maladroit comme méthode d'instance qui se transforme en elle
Sinaesthetic

0

Voici mon implémentation de 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

Si vous allez afficher cette arborescence sur l'interface graphique, vous pouvez utiliser TreeView et TreeNode . (Je suppose que techniquement, vous pouvez créer un TreeNode sans le mettre sur une interface graphique, mais il a plus de surcharge qu'une simple implémentation TreeNode maison.)


-4

Si vous avez besoin d'une implémentation de structure de données d'arborescence enracinée qui utilise moins de mémoire, vous pouvez écrire votre classe Node comme suit (implémentation 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
Publier du code C ++ sur une question spécifiquement pour C # n'est pas la meilleure idée, Jake. Surtout celui qui comprend des pointeurs. Vous savez que les pointeurs sont traqués sans pitié en C #, non? : p
ThunderGr

2
@ThunderGr ce n'est pas juste. Répondre en C # aurait été mieux, mais ces pointeurs C ++ peuvent être compris par les locuteurs C # comme des références (ils sont moins sûrs, ok). Après que David Boike, Aaron Gage, Ronnie Overby, Grzegorz Dev, Berezh et Erik Nagel aient tous suggéré essentiellement la même structure de données avec des différences mineures seulement dans l'expression, Jake a suggéré de décomposer la liste chaînée donnant des structures plus simples avec un seul type de nœud et navigabilité des frères et sœurs. N'exprimez pas votre aversion pour C ++ en votant contre une réponse constructive.
migle

3
@migle Je n'ai pas downvote la réponse (pas de upvote non plus). Et je n'aime pas C ++. J'ai vu que la réponse avait été rejetée sans que personne ne suggère quoi que ce soit à Jake pour savoir pourquoi et comment il améliorerait sa réponse. Il ne s'agit pas "d'être meilleur". La question est balisée pour C # uniquement. Il n'est pas recommandé de publier des réponses dans une autre langue que la balise et certaines personnes voteront contre.
ThunderGr
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.