我有一个类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;
我知道我需要使用递归,但我对它的经验很少。任何帮助搞清楚这个算法都会受到赞赏。
答案 0 :(得分:1)
除非您以某种方式要求使用List<List<iSymbol>>
,否则我建议切换到不同的类结构,使用基类(或接口)Expression
和子类(或实现者)SymbolExpression
,NotExpression
,OrExpression
和AndExpression
。 SymbolExpression
包含单个符号; NotExpression
包含一个Expression
,OrExpression
和AndExpression
各包含两个表达式。对于使用数学表达式,这是一个更标准的结构,在它上面执行转换可能更简单。
使用上述类,您可以将任何表达式建模为二叉树。通过将其子项作为原始根的NotExpression
替换为根来否定表达式。然后,使用深度优先搜索遍历树,每当您点击其子级为NotExpression
或OrExpression
的{{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;
}