/** * 从给点节点开始克隆一条路径<br> * Clones a _transition path from a given node. * * @param pivotConfluenceNode the MDAGNode that the cloning operation is to be based from * @param transitionStringToPivotNode a String which corresponds with a _transition path from * souceNode to {@code pivotConfluenceNode} * @param str a String which corresponds to the _transition path from {@code pivotConfluenceNode} * that is to be cloned */ private void cloneTransitionPath( MDAGNode pivotConfluenceNode, String transitionStringToPivotNode, String str) { MDAGNode lastTargetNode = pivotConfluenceNode.transition( str); // Will store the last node which was used as the base of a cloning operation MDAGNode lastClonedNode = null; // Will store the last cloned node char lastTransitionLabelChar = '\0'; // Will store the char which labels the _transition to lastTargetNode from its parent // node in the prefixString's _transition path // Loop backwards through the indices of str, using each as a boundary to create substrings of // str of decreasing length // which will be used to _transition to, and duplicate the nodes in the _transition path of str // from pivotConfluenceNode. for (int i = str.length(); i >= 0; i--) { String currentTransitionString = (i > 0 ? str.substring(0, i) : null); MDAGNode currentTargetNode = (i > 0 ? pivotConfluenceNode.transition(currentTransitionString) : pivotConfluenceNode); MDAGNode clonedNode; if (i == 0) // if we have reached pivotConfluenceNode { // Clone pivotConfluenceNode in a way that reassigns the _transition of its parent node (in // transitionStringToConfluenceNode's path) to the clone. String transitionStringToPivotNodeParent = transitionStringToPivotNode.substring(0, transitionStringToPivotNode.length() - 1); char parentTransitionLabelChar = transitionStringToPivotNode.charAt(transitionStringToPivotNode.length() - 1); clonedNode = pivotConfluenceNode.clone( sourceNode.transition(transitionStringToPivotNodeParent), parentTransitionLabelChar); ///// } else clonedNode = currentTargetNode.clone(); // simply clone curentTargetNode transitionCount += clonedNode.getOutgoingTransitionCount(); // If this isn't the first node we've cloned, reassign clonedNode's _transition labeled // with the lastTransitionChar (which points to the last targetNode) to the last clone. if (lastClonedNode != null) { clonedNode.reassignOutgoingTransition( lastTransitionLabelChar, lastTargetNode, lastClonedNode); lastTargetNode = currentTargetNode; } // Store clonedNode and the char which labels the _transition between the node it was cloned // from (currentTargetNode) and THAT node's parent. // These will be used to establish an equivalent _transition to clonedNode from the next clone // to be created (it's clone parent). lastClonedNode = clonedNode; lastTransitionLabelChar = (i > 0 ? str.charAt(i - 1) : '\0'); ///// } ///// }
/** * Creates a SimpleMDAGNode version of an MDAGNode's outgoing _transition set in mdagDataArray. * * @param node the MDAGNode containing the _transition set to be inserted in to {@code * mdagDataArray} * @param mdagDataArray an array of SimpleMDAGNodes containing a subset of the data of the MDAG * @param onePastLastCreatedTransitionSetIndex an int of the index in {@code mdagDataArray} that * the outgoing _transition set of {@code node} is to start from * @return an int of one past the end of the _transition set located farthest in {@code * mdagDataArray} */ private int createSimpleMDAGTransitionSet( MDAGNode node, SimpleMDAGNode[] mdagDataArray, int onePastLastCreatedTransitionSetIndex) { int pivotIndex = onePastLastCreatedTransitionSetIndex; // node自己的位置 node.setTransitionSetBeginIndex(pivotIndex); onePastLastCreatedTransitionSetIndex += node.getOutgoingTransitionCount(); // 这个参数代表id的消耗 // Create a SimpleMDAGNode representing each _transition label/target combo in // transitionTreeMap, recursively calling this method (if necessary) // to set indices in these SimpleMDAGNodes that the set of transitions emitting from their // respective _transition targets starts from. TreeMap<Character, MDAGNode> transitionTreeMap = node.getOutgoingTransitions(); for (Entry<Character, MDAGNode> transitionKeyValuePair : transitionTreeMap.entrySet()) { // Use the current _transition's label and target node to create a SimpleMDAGNode // (which is a space-saving representation of the _transition), and insert it in to // mdagDataArray char transitionLabelChar = transitionKeyValuePair.getKey(); MDAGNode transitionTargetNode = transitionKeyValuePair.getValue(); mdagDataArray[pivotIndex] = new SimpleMDAGNode( transitionLabelChar, transitionTargetNode.isAcceptNode(), transitionTargetNode.getOutgoingTransitionCount()); ///// // If targetTransitionNode's outgoing _transition set hasn't been inserted in to mdagDataArray // yet, call this method on it to do so. // After this call returns, transitionTargetNode will contain the index in mdagDataArray that // its _transition set starts from if (transitionTargetNode.getTransitionSetBeginIndex() == -1) onePastLastCreatedTransitionSetIndex = createSimpleMDAGTransitionSet( transitionTargetNode, mdagDataArray, onePastLastCreatedTransitionSetIndex); mdagDataArray[pivotIndex++].setTransitionSetBeginIndex( transitionTargetNode.getTransitionSetBeginIndex()); } ///// return onePastLastCreatedTransitionSetIndex; }
/** * 固化自己<br> * Creates a space-saving version of the MDAG in the form of an array. Once the MDAG is * simplified, Strings can no longer be added to or removed from it. */ public void simplify() { if (sourceNode != null) { mdagDataArray = new SimpleMDAGNode[transitionCount]; createSimpleMDAGTransitionSet(sourceNode, mdagDataArray, 0); simplifiedSourceNode = new SimpleMDAGNode('\0', false, sourceNode.getOutgoingTransitionCount()); // Mark the previous MDAG data structure and equivalenceClassMDAGNodeHashMap // for garbage collection since they are no longer needed. sourceNode = null; equivalenceClassMDAGNodeHashMap = null; ///// } }
/** * 在从给定节点开始的一段路径上执行最小化<br> * Performs minimization processing on a _transition path starting from a given node. * * <p>This entails either replacing a node in the path with one that has an equivalent right * language/equivalence class (defined as set of _transition paths that can be traversed and nodes * able to be reached from it), or making it a representative of a right language/equivalence * class if a such a node does not already exist. * * @param originNode the MDAGNode that the _transition path corresponding to str starts from * @param str a String related to a _transition path */ private void replaceOrRegister(MDAGNode originNode, String str) { char transitionLabelChar = str.charAt(0); MDAGNode relevantTargetNode = originNode.transition(transitionLabelChar); // If relevantTargetNode has transitions and there is at least one char left to process, // recursively call // this on the next char in order to further processing down the _transition path corresponding // to str if (relevantTargetNode.hasTransitions() && !str.substring(1).isEmpty()) replaceOrRegister(relevantTargetNode, str.substring(1)); ///// // Get the node representing the equivalence class that relevantTargetNode belongs to. MDAGNodes // hash on the // transitions paths that can be traversed from them and nodes able to be reached from them; // nodes with the same equivalence classes will hash to the same bucket. MDAGNode equivalentNode = equivalenceClassMDAGNodeHashMap.get(relevantTargetNode); if (equivalentNode == null) // if there is no node with the same right language as relevantTargetNode equivalenceClassMDAGNodeHashMap.put(relevantTargetNode, relevantTargetNode); else if (equivalentNode != relevantTargetNode) // if there is another node with the same right language as // relevantTargetNode, reassign the { // _transition between originNode and relevantTargetNode, to originNode and the node // representing the equivalence class of interest relevantTargetNode.decrementTargetIncomingTransitionCounts(); transitionCount -= relevantTargetNode .getOutgoingTransitionCount(); // Since this method is recursive, the outgoing // transitions of all of relevantTargetNode's child // nodes have already been reassigned, // so we only need to decrement the _transition count by the relevantTargetNode's outgoing // _transition count originNode.reassignOutgoingTransition( transitionLabelChar, relevantTargetNode, equivalentNode); } }
private void splitTransitionPath(MDAGNode originNode, String storedStringSubstr) { HashMap<String, Object> firstConfluenceNodeDataHashMap = getTransitionPathFirstConfluenceNodeData(originNode, storedStringSubstr); Integer toFirstConfluenceNodeTransitionCharIndex = (Integer) firstConfluenceNodeDataHashMap.get("toConfluenceNodeTransitionCharIndex"); MDAGNode firstConfluenceNode = (MDAGNode) firstConfluenceNodeDataHashMap.get("confluenceNode"); if (firstConfluenceNode != null) { MDAGNode firstConfluenceNodeParent = originNode.transition( storedStringSubstr.substring(0, toFirstConfluenceNodeTransitionCharIndex)); MDAGNode firstConfluenceNodeClone = firstConfluenceNode.clone( firstConfluenceNodeParent, storedStringSubstr.charAt(toFirstConfluenceNodeTransitionCharIndex)); transitionCount += firstConfluenceNodeClone.getOutgoingTransitionCount(); String unprocessedSubString = storedStringSubstr.substring(toFirstConfluenceNodeTransitionCharIndex + 1); splitTransitionPath(firstConfluenceNodeClone, unprocessedSubString); } }