符号树的逻辑反演

时间:2012-01-30 22:16:58

标签: c# recursion boolean-logic

我有一个类Symbol_Group,它表示自然AB(C+DE) + FG的可逆表达式。 Symbol_Group包含List<List<iSymbol>>,其中iSymbol是应用于Symbol_Group和Symbol的接口。

上述等式将表示为A,B,Sym_Grp + F,G; Sym_Grp = C + D,E,其中每个+代表一个新的List<iSymbol>

我需要能够使用一种算法来反转和扩展这个等式,该算法可以处理任意数量的嵌套,以及任何数量的符号或ored合在一起,以生成一组Symbol_Group,每个包含一个唯一的扩展。对于上述问题,答案集为!A!F; !B!F; !C!D!F; !C!E!F; !A!G; !B!G; !C!D!G; !C!E!G;

我知道我需要使用递归,但我对它的经验很少。任何帮助搞清楚这个算法都会受到赞赏。

3 个答案:

答案 0 :(得分:1)

除非您以某种方式要求使用List<List<iSymbol>>,否则我建议切换到不同的类结构,使用基类(或接口)Expression和子类(或实现者)SymbolExpressionNotExpressionOrExpressionAndExpressionSymbolExpression包含单个符号; NotExpression包含一个ExpressionOrExpressionAndExpression各包含两个表达式。对于使用数学表达式,这是一个更标准的结构,在它上面执行转换可能更简单。

使用上述类,您可以将任何表达式建模为二叉树。通过将其子项作为原始根的NotExpression替换为根来否定表达式。然后,使用深度优先搜索遍历树,每当您点击其子级为NotExpressionOrExpression的{​​{1}}时,您可以用AndExpression替换它或者AndExpression(分别),其子女为OrExpression s,原始孩子在其下方。您可能还想消除双重否定(查找其子项为NotExpression的{​​{1}},并删除两者)。

(这个答案是否可以理解可能取决于你使用树木的舒适程度。如果你需要澄清,请告诉我。)

答案 1 :(得分:0)

经过大量工作,这是我用来获得最小反演项的方法。

    public List<iSymbol> GetInvertedGroup()
    {
        TrimSymbolList();
        List<List<iSymbol>> symbols = this.CopyListMembers(Symbols);
        List<iSymbol> SymList;
        while (symbols.Count > 1)
        {
            symbols.Add(MultiplyLists(symbols[0], symbols[1]));
            symbols.RemoveRange(0, 2);
        }
        SymList = symbols[0];
        for(int i=0;i<symbols[0].Count;i++)
        {
            if (SymList[i] is Symbol)
            {
                Symbol sym = SymList[i] as Symbol;
                SymList.RemoveAt(i--);
                Symbol_Group symgrp = new Symbol_Group(null);
                symgrp.AddSymbol(sym);
                SymList.Add(symgrp);
            }
        }

        for (int i = 0; i < SymList.Count; i++)
        {
            if (SymList[i] is Symbol_Group)
            {
                Symbol_Group SymGrp = SymList[i] as Symbol_Group;
                if (SymGrp.Symbols.Count > 1)
                {
                    List<iSymbol> list = SymGrp.GetInvertedGroup();
                    SymList.RemoveAt(i--);
                    AddElementsOf(list, SymList);
                }
            }
        }
        return SymList;
    }

    public List<iSymbol> MultiplyLists(List<iSymbol> L1, List<iSymbol> L2)
    {
        List<iSymbol> Combined = new List<iSymbol>(L1.Count + L2.Count);
        foreach (iSymbol S1 in L1)
        {
            foreach (iSymbol S2 in L2)
            {
                Symbol_Group newGrp = new Symbol_Group(null);
                newGrp.AddSymbol(S1);
                newGrp.AddSymbol(S2);
                Combined.Add(newGrp);
            }
        }
        return Combined;
    }

这产生了一组符号组,每组在最终结果中代表1或术语(例如!A!F)。使用了一些进一步的代码将其减少为List&gt;,因为答案中存在合理数量的嵌套。为了减少它,我使用了:

    public List<List<Symbol>> ReduceList(List<iSymbol> List)
    {
        List<List<Symbol>> Output = new List<List<Symbol>>(List.Count);
        foreach (iSymbol iSym in List)
        {
            if (iSym is Symbol_Group)
            {
                List<Symbol> L = new List<Symbol>();
                (iSym as Symbol_Group).GetAllSymbols(L);
                Output.Add(L);
            }
            else
            {
                throw (new Exception());
            }
        }
        return Output;
    }

    public void GetAllSymbols(List<Symbol> List)
    {
        foreach (List<iSymbol> SubList in Symbols)
        {
            foreach (iSymbol iSym in SubList)
            {
                if (iSym is Symbol)
                {
                    List.Add(iSym as Symbol);
                }
                else if (iSym is Symbol_Group)
                {
                    (iSym as Symbol_Group).GetAllSymbols(List);
                }
                else
                {
                    throw(new Exception());
                }
            }
        }
    }

希望这有助于其他人!

答案 2 :(得分:0)

经过一些重新调整,我找到了这个更简单的解决方案。我希望它可以解决其他有类似问题的人!这是类结构(加上一些其他属性)

public class SymbolGroup : iSymbol
{

    public SymbolGroup(SymbolGroup Parent, SymRelation Relation)
    {
        Symbols = new List<iSymbol>();
        this.Parent = Parent;
        SymbolRelation = Relation;
        if (SymbolRelation == SymRelation.AND)
            Name = "AND Group";
        else
            Name = "OR Group";
    }

    public int Depth
    {
        get
        {
            foreach (iSymbol s in Symbols)
            {
                if (s is SymbolGroup)
                {
                    return (s as SymbolGroup).Depth + 1;
                }
            }
            return 1;
        }
    }
}

反转方法也包含在这个类中。它将结果列表中的未展开组替换为该结果的所有扩展结果。它一次只剥离一个级别。

    public List<SymbolGroup> InvertGroup()
    {
        List<SymbolGroup> Results = new List<SymbolGroup>();

        foreach (iSymbol s in Symbols)
        {
            if (s is SymbolGroup)
            {
                SymbolGroup sg = s as SymbolGroup;
                sg.Parent = null;
                Results.Add(s as SymbolGroup);
            }
            else if (s is Symbol)
            {
                SymbolGroup sg = new SymbolGroup(null, SymRelation.AND);
                sg.AddSymbol(s);
                Results.Add(sg);
            }
        }

        bool AllChecked = false;
        while (!AllChecked)
        {
            AllChecked = true;
            for(int i=0;i<Results.Count;i++) 
            {
                SymbolGroup result = Results[i];
                if (result.Depth > 1)
                {
                    AllChecked = false;
                    Results.RemoveAt(i--);
                }
                else
                    continue;

                if (result.SymbolRelation == SymRelation.OR)
                {
                    Results.AddRange(result.MultiplyOut());
                    continue;
                }

                for(int j=0;j<result.nSymbols;j++)
                {
                    iSymbol s = result.Symbols[j];
                    if (s is SymbolGroup)
                    {
                        result.Symbols.RemoveAt(j--);   //removes the symbolgroup that is being replaced, so that the rest of the group can be added to the expansion.
                        AllChecked = false;
                        SymbolGroup subResult = s as SymbolGroup;
                        if(subResult.SymbolRelation == SymRelation.OR)
                        {
                            List<SymbolGroup> newResults;
                            newResults = subResult.MultiplyOut();
                            foreach(SymbolGroup newSg in newResults)
                            {
                                newSg.Symbols.AddRange(result.Symbols);
                            }
                            Results.AddRange(newResults);
                        }
                        break;
                    }
                }
            }
        }
        return Results;
    }