/// <summary> /// Соединение 2 поддеревьев /// </summary> /// <param name="t2">Поддерево из 2 узлов</param> /// <param name="tree">Поддерево с корнем в листе первого</param> /// <param name="depth">Глубина</param> private void Connect2Subtrees(Tree t2, Tree tree, int depth) { Debug.Assert(t2.Size == 2); string[] preList = t2.ConnectDfsRepresentation(tree); Tree child = Tree.Create(preList, true, SearchParams.Support); ExtendedSubtrees.AddSubtree(child); int depthC = depth + 1; // Глубина соединения while (--depthC >= 0) { if (!t2.ContainsDepth(depthC)) { continue; } int depthTree = depthC + 1; if (!tree.ContainsDepth(depthTree)) { continue; } foreach (TreeEntries tSet in t2[depthC].GetTreeEntries()) { if (!tree.ContainsTreeAtDepth(depthTree, tSet.TreeId)) { continue; } foreach (RootEntry root in tSet.GetRootEntries()) { foreach (SubtreeEntry t2Entry in root.RightMostList) { if (!tree[depthTree][tSet.TreeId].RootDictionary.ContainsKey(t2Entry.SecondIndex)) { continue; } var newEntry = t2Entry.Connect(tree[depthTree][tSet.TreeId][t2Entry.SecondIndex].FirstEntry); child.AddEntry(newEntry); } } } } if (!child.IsFrequent) { return; } FrequentSubtrees.AddFrequentSubtree(child); child.Father = t2; child.Mother = tree; }
/// <summary> /// Комбинирование 2 поддеревьев /// </summary> /// <param name="xTree">Первое поддерево</param> /// <param name="yTree">Второе поддерево</param> /// <param name="depth">Глубина</param> /// <returns>Новое поддерево, полученное путем комбинирования</returns> private Tree Combine2Subtrees(Tree xTree, Tree yTree, int depth) { string[] dfsList = xTree.CombineDfsRepresentation(yTree); Tree child = Tree.Create(dfsList, false, SearchParams.Support); ExtendedSubtrees.AddSubtree(child); int curDepth = depth + 1; while (--curDepth >= 0) { if (!xTree.ContainsDepth(curDepth) || !yTree.ContainsDepth(curDepth)) { continue; } foreach (TreeEntries tSet in xTree[curDepth].GetTreeEntries()) { if (!yTree.ContainsTreeAtDepth(curDepth, tSet.TreeId)) { continue; } foreach (RootEntry root in tSet.GetRootEntries()) { if (!yTree.ContainsRootIndex(curDepth, tSet.TreeId, root.RootIndex)) { continue; } SubtreeEntry xEntry = xTree.GetEntry(curDepth, tSet.TreeId, root.RootIndex); SubtreeEntry yEntry = yTree.GetFirstEntryAfterSpecifiedIndex(xEntry.Depth, xEntry.TreeId, xEntry.RootIndex, xEntry.RightMostIndex); if (yEntry == null) { continue; } child.AddEntry(xEntry.Combine(yEntry)); } } } if (!child.IsFrequent) { return(null); } FrequentSubtrees.AddFrequentSubtree(child); child.Father = xTree; child.Mother = yTree; return(child); }
/// <summary> /// Соединение поддеревьев на заданной глубине /// </summary> /// <param name="depth">Глубина</param> protected override void Connect(int depth) { List <Tree> connectableTrees = FrequentSubtrees.GetConnectableAtDepth(depth); List <Tree> treesToBeConnected = FrequentSubtrees.GetToBeConnectableAtDepth(depth + 1); foreach (Tree f2 in connectableTrees) { List <Tree> toBeConnected = SelectSubtreesOfSameRoot(f2.SecondSymbol, treesToBeConnected, depth + 1); foreach (Tree t in toBeConnected) { string childDfsStr = f2.ConnectDfsRepresentation(t).ToDfsString(); if (ExtendedSubtrees.AlreadyExtended(childDfsStr)) { continue; } if (!f2.HasNewConnectEntryAtDepth(t, depth)) { continue; } Connect2Subtrees(f2, t, depth); } } PruneAfterConnection(FrequentSubtrees, SearchParams.Support, depth); }
/// <summary> /// Обход с целью комбинирования поддеревьев /// </summary> /// <param name="xTree">Дерево, с которым производится комбинация</param> /// <param name="yIndex">Индекс дерева в списке</param> /// <param name="group">Список деревьев, которые можно комбинировать с xTree</param> /// <param name="depth">Глубина</param> private void Traversal(Tree xTree, int yIndex, IList <Tree> group, int depth) { Tree treeX = xTree; Tree treeY = group[yIndex]; string childDfsStr = treeX.CombineDfsRepresentation(treeY).ToDfsString(); Tree child = null; if (ExtendedSubtrees.AlreadyExtended(childDfsStr)) { child = FrequentSubtrees.GetSubtreeAtDepth(childDfsStr, depth); } else if (treeX.HasNewCombineEntryAtDepth(treeY, depth)) { child = Combine2Subtrees(treeX, treeY, depth); } if (child == null) { return; } for (int i = 0; i < group.Count; i++) { Traversal(child, i, group, depth); } }
/// <summary> /// Получение поддеревьев из 1 и 2 узлов /// </summary> /// <param name="tn">Корень дерева</param> /// <param name="maxDepth">Максимальная глубина</param> private void Get1NodeAnd2NodesTrees(TreeNode tn, ref int maxDepth) { if (maxDepth <= tn.Depth) { maxDepth = tn.Depth; } string treeId = tn.Tree.TreeId; var dfsList1Node = new[] { tn.Tag, TextTreeEncoding.UpSign.ToString() }; var subtreeKey1Node = dfsList1Node.ToDfsString(); if (!OneNodeTrees.ContainsKey(subtreeKey1Node)) { Tree oneNodeTree = Tree.Create(dfsList1Node, false, SearchParams.Support); ExtendedSubtrees.AddSubtree(oneNodeTree); OneNodeTrees.Add(oneNodeTree.DfsString, oneNodeTree); } OneNodeTrees[subtreeKey1Node].AddEntry(SubtreeEntry.Create(treeId, tn.Depth, new[] { tn.DfsIndex })); if (tn.Children == null) { return; } foreach (TreeNode child in tn.Children) { var dfsList2Nodes = new[] { tn.Tag, child.Tag, TextTreeEncoding.UpSign.ToString(), TextTreeEncoding.UpSign.ToString() }; var subtreeKey2Nodes = dfsList2Nodes.ToDfsString(); if (!TwoNodeTrees.ContainsKey(subtreeKey2Nodes)) { Tree twoNodesTree = Tree.Create(dfsList2Nodes, true, SearchParams.Support); ExtendedSubtrees.AddSubtree(twoNodesTree); TwoNodeTrees.Add(twoNodesTree.DfsString, twoNodesTree); } SubtreeEntry entry = SubtreeEntry.Create(treeId, tn.Depth, new[] { tn.DfsIndex, child.DfsIndex }); TwoNodeTrees[subtreeKey2Nodes].AddEntry(entry); Get1NodeAnd2NodesTrees(child, ref maxDepth); } }