/** * 从给点节点开始克隆一条路径<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'); ///// } ///// }
/** * 在从给定节点开始的一段路径上执行最小化<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); } }