我为Redundancy Department算法创建了此代码,它从文件中获取数据,并检查每个集合是否存在重复的FD(Functional Dependency),它工作正常,但是具有26的循环复杂度,可以通过任何方式即使我试图将if条件重构为无效的方法也要减少它 Here you find the Explanation of the algorithm
public struct node
{
public string left;
public string right;
}
public static bool CheckRedondance(List<node> listNodes)
{
bool resultat = false;
for (int i = 0; i < listNodes.Count; i++) //pour parcourir les DF du groupe
{
for (int j = i + 1; j < listNodes.Count; j++) //pour parcourir le reste du groupe
{
if (listNodes[i].left == listNodes[j].left) // pour trouver la partie gauche egale
{
for (int k = 0; k < listNodes.Count; k++)
{
if (listNodes[k].left == listNodes[i].right)
{
Console.WriteLine("en commun : " + listNodes[k].left + "->" + listNodes[k].right + " avec " + listNodes[i].left + "->" + listNodes[i].right);
if (listNodes[k].right == listNodes[j].right)
{
Console.WriteLine("redondance dans " + listNodes[j].left + "->" + listNodes[j].right);
resultat = true;
}
}
}
}
}
}
return resultat;
}
public static bool CheckRedondance2(List<node> listNodes)
{
bool resultat = false;
node nouvelleDF;
nouvelleDF.right = "";
nouvelleDF.left = "";
for (int i = 0; i < listNodes.Count; i++)
{
for (int j = i + 1; j < listNodes.Count; j++)
{
if (listNodes[j].left.Contains(listNodes[i].left))
{
if (listNodes[j].left.Length > 1)
{
string concatD, concatG;
concatG = listNodes[i].left + listNodes[j].left.Substring(1, listNodes[j].left.Length - 1);
concatD = listNodes[i].right + listNodes[j].left.Substring(1, listNodes[j].left.Length - 1);
if (concatD.Contains(listNodes[j].right))
{
Console.WriteLine("partie 2 :" + concatG + "->" + concatD);
nouvelleDF.right = listNodes[j].right;
nouvelleDF.left = concatG;
Console.WriteLine("nouvelle df " + nouvelleDF.left + "->" + nouvelleDF.right);
// concatD = /*listNodes[i].right;*/ listNodes[i].right + listNodes[j].left.Substring(1, listNodes[j].left.Length-1);
int nbIterations = 0; //pour connaitre l'existance de la même DF
for (int k = 0; k < listNodes.Count; k++) //recherche de la nouvelle DF dans la liste et trouver la redondance du resultat
{
if ((listNodes[k].right == nouvelleDF.right) && ((listNodes[k].left == nouvelleDF.left)))
{
nbIterations = nbIterations + 1;
if (nbIterations == 1)
{
Console.WriteLine("redondance dans " + listNodes[k].left + "->" + listNodes[k].right);
resultat = true;
}
}
}
}
}
}
}
}
return resultat;
}
static void Main()
{
var lines = File.ReadAllLines(@"C:/input.txt"); //lecture du fichier input
int i = 0; //la ligne du fichier
int nb = 0; //la longueur de chaque groupe (et sera ecrasée à chaque fois)
List<node> listNodes = new List<node>(); //les DF de chaque groupe (node est une DF)
int numEnsemble = 0;
while (i < lines.Length)
{
var line = lines[i];
if (!line.Contains("->"))
{
nb = Int32.Parse(line);
if (nb != 0)
{
numEnsemble++;
Console.WriteLine(" ");
Console.WriteLine("Ensemble numero " + numEnsemble);
//Console.WriteLine(nb);
for (int j = i; j <= i + nb; j++) //new groupe
{
var groupLine = lines[j];
if (groupLine.Contains("->"))
{
node localNode; //expl: A->BC
string[] parts = groupLine.Split(new string[] { "->" }, StringSplitOptions.None);
localNode.left = parts[0].Trim(); //expl:A
localNode.right = parts[1].Trim();//expl: BC
Console.WriteLine(localNode.left + "->" + localNode.right);
listNodes.Add(localNode);
}
}
if (!CheckRedondance(listNodes)) //premiere Methode expl: A->BD / BD->C / A->C
{
if (!CheckRedondance2(listNodes)) //2eme Meth: expl: P->RST / PS->T
{
Console.WriteLine("Pas de redondance");
}
}
listNodes.Clear();
i += nb;
}
}
else
{
i++;
}
}
Console.ReadLine();
}
答案 0 :(得分:1)
因此,使用查找数据结构可以更有效地完成此操作。据我所知,您正在寻找是否至少有一组3个节点与node1.left = node2.left && node3.left == node1.right && node3.right == node2.right
的需求相匹配
因此,您将建立一个查找结构,在其中填充可以创建匹配项的数据,然后检查是否找到了匹配项。
现在可以进一步优化它,但是您可以尝试类似的方法(使用我的测试数据,我得到的结果与您的CheckRedondance
相同,但是速度更快:
public static bool CheckRedondanceEfficient(List<node> listNodes)
{
var nodeLookup = new Dictionary<string, List<node>>();
var matchLookup = new Dictionary<string, HashSet<string>>();
foreach (node node in listNodes)
{
if (AddNode(node, nodeLookup, matchLookup))
return true;
}
foreach (node node in listNodes)
{
if (matchLookup.TryGetValue(node.left, out HashSet<string> hashLookup) && hashLookup.Contains(node.right))
return true;
}
return false;
}
private static bool AddNode(node node, Dictionary<string, List<node>> nodeLookup, Dictionary<string, HashSet<string>> matchLookup)
{
if (matchLookup.TryGetValue(node.left, out HashSet<string> hashLookup) && hashLookup.Contains(node.right))
return true;
if (nodeLookup.TryGetValue(node.left, out List<node> nodeMatches))
{
foreach (node first in nodeMatches)
{
AddFirstMatch(first, node, matchLookup);
}
nodeMatches.Add(node);
}
else
{
nodeLookup.Add(node.left, new List<node>()
{
node
});
}
return false;
}
private static void AddFirstMatch(node nodeFirst, node nodeSecond, Dictionary<string, HashSet<string>> matchLookup)
{
HashSet<string> firstMatch;
if (!matchLookup.TryGetValue(nodeFirst.right, out firstMatch))
{
firstMatch = new HashSet<string>();
matchLookup.Add(nodeFirst.right, firstMatch);
firstMatch.Add(nodeSecond.right);
}
else
firstMatch.Add(nodeSecond.right);
}
答案 1 :(得分:0)
1)想法,而不是完整的解决方案:
如何更改文件中的第一种结构?
public struct node
{
public List<string> conns;
}
然后您可以使用类似的内容:
foreach (string element in nodeRight.conns) {
if (nodeLeft.conns.Contains(element))
{
/*...*/
}
}
在一个节点的左侧或右侧建立连接对您来说是否很重要?如果没有,这对您来说很平常。通过这种方式,我认为您可以在那里保存一个。您只能通过仅使用标准函数来检查值是否在列表中。
2)另一个想法: 我不确定根据任务逻辑是否可行,但是回溯算法又如何呢? (https://en.wikipedia.org/wiki/Backtracking)
您将更改结构(为公式中的每个成员添加bool标志),并在其被访问时提供true的递归调用和标记,或者如果多次访问任何成员,则使用方法外的另一个标志进行特殊返回。
处理后,另一个设置标志将再次重置为false。