web-dev-qa-db-fra.com

Créez une structure de données arborescente simple et hautes performances en c #

J'ai besoin de créer un catalogue de produits, sous forme d'arborescence.

chaque nœud d'arbre présente par un ID (chaîne), les fonctions sur les données d'arbre seulement 2:

  1. getChild(string ID), donner un ID, obtenir des enfants (pas besoin d'inclure les enfants des enfants), si l'ID est nul, obtenir tous les nœuds racine
  2. getParent(string ID), retourne l'ID parent si have, ou null si est root

Depuis qu'une fois l'arbre décidé, ne changera pas, donc je pense que mettre tout le code en statique sera le meilleur. Je commence donc à essayer d'utiliser le dictionnaire

"id": {parent:ID, child:[id2, id3, id4....]}

Depuis theres environ 1000+ catalogue, j'ai trouvé que je me gâche rapidement, beaucoup d'erreurs dans les données statiques et rend le résultat final utilisable. De plus, maintenant je n'en ai écrit que des dizaines et le code ressemble à du gâchis.

Veuillez conseiller une manière de créer cette arborescence de catalogue simple avec de hautes performances. Merci

27
Eric Yin

Faites-en juste un cours.

MISE À JOUR:

class TreeNode : IEnumerable<TreeNode>
{
    private readonly Dictionary<string, TreeNode> _children =
                                        new Dictionary<string, TreeNode>();

    public readonly string ID;
    public TreeNode Parent { get; private set; }

    public TreeNode(string id)
    {
        this.ID = id;
    }

    public TreeNode GetChild(string id)
    {
        return this._children[id];
    }

    public void Add(TreeNode item)
    {
        if (item.Parent != null)
        {
            item.Parent._children.Remove(item.ID);
        }

        item.Parent = this;
        this._children.Add(item.ID, item);
    }

    public IEnumerator<TreeNode> GetEnumerator()
    {
        return this._children.Values.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    public int Count
    {
        get { return this._children.Count; }
    }
}

L'utilisation sera assez simple à définir statiquement:

var tree = new TreeNode("Root")
               {
                   new TreeNode("Category 1")
                       {
                           new TreeNode("Item 1"),
                           new TreeNode("Item 2"),
                           new TreeNode("Item 3"),
                       },
                   new TreeNode("Category 2")
                       {
                           new TreeNode("Item 1"),
                           new TreeNode("Item 2"),
                           new TreeNode("Item 3"),
                           new TreeNode("Item 4"),
                       }
               };

Modifier

Encore plus de fonctionnalités pour une création encore plus facile ...

public static TreeNode BuildTree(string tree)
{
    var lines = tree.Split(new[] { Environment.NewLine },
                           StringSplitOptions.RemoveEmptyEntries);

    var result = new TreeNode("TreeRoot");
    var list = new List<TreeNode> { result };

    foreach (var line in lines)
    {
        var trimmedLine = line.Trim();
        var indent = line.Length - trimmedLine.Length;

        var child = new TreeNode(trimmedLine);
        list[indent].Add(child);

        if (indent + 1 < list.Count)
        {
            list[indent + 1] = child;
        }
        else
        {
            list.Add(child);
        }
    }

    return result;
}

public static string BuildString(TreeNode tree)
{
    var sb = new StringBuilder();

    BuildString(sb, tree, 0);

    return sb.ToString();
}

private static void BuildString(StringBuilder sb, TreeNode node, int depth)
{
    sb.AppendLine(node.ID.PadLeft(node.ID.Length + depth));

    foreach (var child in node)
    {
        BuildString(sb, child, depth + 1);
    }
}


Utilisation:

var tree = TreeNode.BuildTree(@"
Cat1
 Sub1
  Item1
  Item2
  Item3
 Sub2
  Item1
  Item2
Cat2
 Sub1
 Sub2
  Item1
  Item2
 Sub3
  Item1
Cat3
Cat4");
55
SimpleVar

J'ai créé un Node class qui pourrait être utile. Il est rapide et possède des propriétés supplémentaires, comme:

  • Les ancêtres
  • Descendance
  • Frères et sœurs
  • Niveau du nœud
  • Parent
  • Root
  • Etc.
13
Alex Siepman

Vous pouvez écrire un simple arbre binaire, j'écris le pseudo-code ci-dessous:

class TreeNode {
    TreeNode Right;
    TreeNode Left;
    int id;
    //...
}

class BinTree {

    void Insert(TreeNode node)
    {
        while(true) {   
            if(node.id > target.id) {
                if(target.Right != null) {
                    target = target.Right;
                    continue;
                }
                else {
                    target.Right = node;
                    break;
                }
            }

            else if(node.id < target.id) {
                if(target.Left != null) {
                    target = target.Left;
                    continue;
                }
                else {
                    target.Left = node;
                    break;
                }   
            }

            else {
                throw new ArgumentException("Duplicated id");
            }
        }
    }


    TreeNode Search(int id)
    {
        TreeNode target = root;

        while(target != null) {
            if(id > target.id) {
                target = target.Right;
            }
            else if(id < target.id) {
                target = target.Left;
            }
            else {
                return target;
            }
        }

        return null;
    }

}

Mais si votre nombre de données est très élevé, l'arborescence AVL est peut-être plus efficace

1
llj098