无论如何有降低算法C#复杂度的方法

时间:2018-12-09 18:37:29

标签: c#

我为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();
    }

2 个答案:

答案 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。