J'ai besoin d'une arborescence qui prend en charge "et" et "ing. Par exemple, étant donné une expression régulière comme Donc, au début, nous avons deux "ou" branches ... peut soit descendre Faire une structure d'arbre est facile, vous avez simplement quelque chose comme p> mais comment savez-vous si les enfants doivent être "anded" ou "oré"? Je suppose que chaque niveau de l'arbre devrait alterner entre "anding" et "oring" p> c'est logique? Quelqu'un peut-il suggérer une structure pour cela? P> Quelques personnes ont suggéré de stocker l'opérateur sur le nœud, qui va bien, mais ce n'est pas un moyen de tirer parti du fait que Chaque niveau alterne toujours ou, et, et, et, et ...? P> EDIT: STRUT> Pas tout à fait sûr pourquoi les gens continuent à supposer qu'il s'agisse d'un arbre binaire. ce n'est pas em>. J'espérais que le petit extrait de code vous inclinait. L'exemple juste arrive em> n'a que 2 branches. P> actuellement penché vers cette: p> AB | C (d | e) code> Je veux transformer cela dans un arbre. AB code>, ou c (d | e) code>. Si vous dirigez la branche AB code>, vous obtenez deux nœuds, A code> et em> B code> (ou a code> suivi de B code>, peu importe). Ensuite, si vous descendez la branche c (d | e) code>, vous obtenez C code> et em> (d | e) code >, alors (d | e) code> est divisé en d code> ou em> e code>. p>
p>
7 Réponses :
abstract class Node { }
class DataNode : Node {
public string Data { get; }
// details
}
class OperatorNode : Node {
public Node Left { get; }
public Node Right { get; }
public BinaryOperator Operator { get; }
// details
}
abstract class BinaryOperator { // details }
class Or : BinaryOperator { // details }
class And : BinaryOperator { // details }
Alors, comment l'exemple d'AB | C (D | E) serait-il mis en œuvre?
Notez également que ce n'est pas un arbre binaire, mais c'est une solution facile. Et où sont les "données" stockées? Seules les feuilles ont des données ... juste le mettre dans le nœud et le laisser comme null à moins que sa feuille?
Y a-t-il quelque chose de mal avec ceci:
Node root = new Node
{
operation = Operation.Or,
children = new Node[]
{
new Node
{
operation = Operation.And,
children = new Node[]
{
new Node{ element = "a" },
new Node{ element="b" }
}
},
new Node
{
children = new Node[]
{
new Node{ element = "c"},
new Node
{
operation= Operation.Or,
children = new Node[]
{
new Node{ element= "d"},
new Node{element = "e"}
}
}
}
}
}
};
Comment l'exemple AB | C (D | E) serait-il mis en œuvre?
@MBeckish: J'aime mieux votre approche, séparant mon numéro code> type code> en deux types (et chaque nouveau noeud code> serait remplacé par nouvel opérateurNode code> ou nouvel élémentnode code>
Je l'ai fait il y a quelques jours à l'aide de antlr . Antlr m'a fourni une grammaire qui est représentée comme une arborescence de syntaxe AST abstraite que vous venez de décrire et généré C # code pouvant gérer cette grammaire. P>
C'est assez agréable et élégant. Voici un quelques exemple . P>
Vous pouvez avoir 2 types de nœuds: nœuds de l'opérateur et nœuds variables.
Les feuilles de votre arbre seront tous des nœuds variables; Tous les autres nœuds seraient des nœuds de l'opérateur. P>
Les nœuds d'opérateur binaires auraient deux enfants. Opérateur unaire (comme non) Les nœuds auraient 1 enfant. P>
pour votre exemple AB | C (D | E): P>
OR
/ \
AND AND
/ \ / \
a b c OR
/ \
d e
Programmatiquement cela semble tout droit à mettre en œuvre. L'analyse impliquerait le démarrage et la plus grande feuille et les nœuds traversants.
Juste pour lancer un peu différent
interface Node
{
// top level operations here
}
class OpNode : Node
{
public Node Left { get; set; }
public Node Right { get; set; }
}
class AndNode : OpNode
{
public AndNode(Node left, Node right)
{
Left = left;
Right = right;
}
public override string ToString()
{
return "(" + Left.ToString() + " & " + Right.ToString() + ")";
}
}
class OrNode : OpNode
{
public OrNode(Node left, Node right)
{
Left = left;
Right = right;
}
public override string ToString()
{
return "(" + Left.ToString() + " | " + Right.ToString() + ")";
}
}
class DataNode<T> : Node
{
T _data;
public DataNode(T data)
{
_data = data;
}
public override string ToString()
{
return _data.ToString();
}
}
Cela ressemble à la solution de Mbeckish, mais vous avez également pris une étape plus loin et divisez les nœuds OP dans deux types différents.
Que diriez-vous de quelque chose de ce simple: chaque classe pourrait avoir son propre Vous voudrez peut-être toujours avoir une superclasse parent afin que votre code puisse contenir des nœuds génériques sans se soucier de savoir si le premier était et ou ou. p> p> évaluer () code> qui serait et ou tous les enfants comme si nécessaire P>
C'est la seule solution jusqu'à présent qui force une alternance ... et c'est simple. Je l'aime bien.
Pensez à une structure d'arborescence où chaque nœud représente une expression booléenne qui peut être évaluée pour être véridique ou fausse - dans votre cas une expression régulière (correspondance ou non-match).
La structure des arbres elle-même représente et et ou:
Chaque route, en commençant par le nœud racine et se terminant par un nœud qui n'a aucun autre enfant, est une conjonction d'expressions, représentant et.
L'arborescence représenterait A et B et c. P> Chaque fois qu'un nœud a plus d'un nœud enfant, il y a une ou (disjonction), ramifiant dans plusieurs routes : p> représente a et ((b et c) ou d) p> de sorte que vous ne devez même pas stocker les opérateurs nulle part. p > Dans votre exemple, vous avez l'expression ab | c (d | e) code> donc il n'y a pas d'expression racine commune à évaluer; Je suggère que la racine dans ce cas est simplement true code> et l'arbre ressemblerait à: p> true
/ \
A C
/ / \
B D E
J'aime ça!! Il supprime la nécessité de garder une trace de l'alternance ou des opérateurs, et sa lecture propre et facile à lire.
Je pense que l'alternance et / ou les niveaux est juste une coïncidence pour cet exemple. En général, vous devriez être capable de mélanger et et au même niveau. Voir ma réponse.
@mbeckish: Est-ce? Pouvez-vous fournir un exemple où vous ne serait pas i> alterner?
De plus, vous n'avez pas besoin d'un éventail d'enfants (sauf si vous allez soutenir les opérateurs N-ARY).
@RRALPH: A | B | C est un exemple trivial.
@MBeckish: Non ... c'est juste une couche avec 3 branches. Personne n'a dit que c'était un arbre binaire. C'est pourquoi j'ai utilisé un tableau dans mon exemple.
@RRALPH - Si vous souhaitez effondrer plusieurs opérateurs binaires dans un seul nœud N-Ary, vous pourrez peut-être assumer des couches alternées.
@RRALPH - En ce qui concerne votre édition, je pense que beaucoup de gens le modéliseraient comme un arbre binaire, car les opérateurs sont binaires (ou unis si vous soutenez pas)!
@MBeckish: la première phrase lit "Compte tenu de l'expression régulière". Cela indique que j'utilise des opérateurs de regex, pas d'autre type binaire.
@Alph - n'a pas analysé ce petit texte. De plus, le titre dit "et ou arbre". Peut-être que vous pouvez le changer pour le rendre plus évident que vous souhaitez analyser les expressions générales régulières dans un arbre (que je pense ajouterait beaucoup plus de complications).
@RRALPH - Plus, "AB" n'est pas "A et B" dans une expression régulière - c'est "A suivi de B". Maintenant, je suis vraiment confondu de ce que vous demandez.
@MBeckish: Je ne voulais pas mettre aussi i> beaucoup d'accentues sur cela ... J'ai déjà réussi à analyser le rep sans utiliser d'arbres ... Eh bien, un arbre de 2 niveaux + récursion, Mais je pense avoir besoin d'une nouvelle structure pour ajouter d'autres fonctionnalités. Je n'ai besoin que de soutien pour les 2 opérateurs (je pense).
Comment vous faites (A | B | C) (DE) avec chaque niveau d'arbre et ou ou seulement?
@ Hpt: vous mettez
d code>,E code> et un "ou" nœud de la même ligne (et-d ensemble), puisa code> ,B code>,C code> sur la ligne suivante (OR). Cela fonctionne, mais vous avez laissé entendre un autre problème que nous avons perdu les informations de regroupement autour de(de) code> (comme si les crochets ne sont pas là ... ce qui est parfaitement bien jusqu'à ce que vous ayez faire des références de retour)@RRALPH: Concernant votre dernier commentaire: Vous jouez maintenant avec l'entrée plutôt que de l'analyser. Si vous souhaitez réduire la chaîne initiale avant de l'analyser, c'est une option, mais c'est mauvais. PS - De quelle classe s'agit-il?
@Norla: Que veux-tu dire? J'allais analyser la corde dans un arbre, puis l'évaluer. Pourquoi est-ce une mauvaise approche? Voilà comment les analyseurs sont écrits, apparemment. Ceci est tout pour Stackoverflow.com/questions/4298541