00001 /* 00002 * (c) copyright 2008, Technische Universitaet Graz and Technische Universitaet Wien 00003 * 00004 * This file is part of jdiagengine. 00005 * 00006 * jdiagengine is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * jdiagengine is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * You should have received a copy of the GNU General Public License 00016 * along with jdiagengine. If not, see <http://www.gnu.org/licenses/>. 00017 * 00018 * Authors: Joerg Weber, Franz Wotawa 00019 * Contact: jweber@ist.tugraz.at (preferred), or fwotawa@ist.tugraz.at 00020 * 00021 */ 00022 00023 00024 package utils; 00025 00026 import java.util.*; 00027 00028 00029 public class DoubleLinkedTree { 00030 00031 protected long lastId = -1; 00032 00033 protected DoubleLinkedTreeNode root; 00034 00035 protected int size = 0; 00036 00037 00038 00039 public DoubleLinkedTree(int initialCapacity) { 00040 } 00041 00042 public void addNode(DoubleLinkedTreeNode newNode, DoubleLinkedTreeNode parent) { 00043 assert((root == null) || (parent != null)); 00044 00045 ++lastId; 00046 newNode.setId(lastId); 00047 00048 if (root == null) { 00049 root = newNode; 00050 } 00051 if (parent != null) { 00052 newNode.setParent(parent); 00053 parent.addChild(newNode); 00054 } 00055 00056 ++size; 00057 //nodes.put(newNode.id, newNode); 00058 } 00059 00060 public int size() { 00061 return size; 00062 } 00063 00064 /* 00065 * Returns an iterator for the entire tree. 00066 * 00067 * Pre-order iteration: the nodes are returned in the same order as they are visited by visitChildrenPreOrder(). 00068 */ 00069 public Iterator iterator() { 00070 return new DoubleLinkedTreeIterator(root); 00071 } 00072 00073 /* 00074 * Like iterator(), but only startNode and its descendants are iterated. 00075 */ 00076 public Iterator iterator(DoubleLinkedTreeNode startNode) { 00077 return new DoubleLinkedTreeIterator(startNode); 00078 } 00079 00080 public void visitChildrenPreOrder(DoubleLinkedTreeNode node, 00081 DoubleLinkedTreeVisitor visitor) { 00082 00083 visitChildrenPreOrder_Recursive(node, visitor); 00084 } 00085 00086 public void visitChildrenPreOrder_Recursive(DoubleLinkedTreeNode node, 00087 DoubleLinkedTreeVisitor visitor) { 00088 00089 visitor.visit(node); 00090 boolean moreNodes = visitor.wantMoreNodes(); 00091 if (moreNodes) { 00092 Iterator itChildren = node.getChildrenIterator(); 00093 while (moreNodes && itChildren.hasNext()) { 00094 DoubleLinkedTreeNode child = (DoubleLinkedTreeNode)itChildren.next(); 00095 visitChildrenPreOrder_Recursive(child, visitor); 00096 moreNodes = visitor.wantMoreNodes(); 00097 } 00098 } 00099 } 00100 00101 /* 00102 * Remove leafNode which MUST really be a leaf. 00103 */ 00104 public void removeLeafNode(DoubleLinkedTreeNode leafNode) { 00105 assert(leafNode.isLeafNode()); 00106 //assert(nodes.containsKey(leafNode.id)); 00107 00108 DoubleLinkedTreeNode parent = leafNode.getParent(); 00109 if (parent != null) parent.removeChild(leafNode); 00110 else { 00111 assert(leafNode == root); 00112 root = null; 00113 } 00114 //nodes.remove(leafNode.id); 00115 } 00116 00117 /* 00118 * Removes node and all of its descendants from this tree. 00119 */ 00120 public void removeNodeAndDescendants(DoubleLinkedTreeNode node) { 00121 DoubleLinkedTreeNode parent = node.getParent(); 00122 if (parent != null) parent.removeChild(node); 00123 else { 00124 assert(node == root); 00125 root = null; 00126 } 00127 //removeRecursive(node); 00128 } 00129 00130 /* 00131 * Creates a list containing all nodes of this tree. 00132 * 00133 * The order of the resulting list is not guaranteed. 00134 * Note that this method is computationally expensive, as the list must be created from scratch. 00135 */ 00136 public List composeNodeList() { 00137 ArrayList result = new ArrayList(size()); 00138 00139 DoubleLinkedTreeIterator itNodes = new DoubleLinkedTreeIterator(root); 00140 while (itNodes.hasNext()) { 00141 Object node = itNodes.next(); 00142 result.add(node); 00143 } 00144 00145 return result; 00146 } 00147 00148 /* 00149 protected removeRecursive(DoubleLinkedTreeNode node) { 00150 00151 Iterator itChildren = node.getChildrenIterator(); 00152 while (itChildren.hasNext()) { 00153 DoubleLinkedTreeNode child = (DoubleLinkedTreeNode)itChildren.next(); 00154 removeRecursive(child); 00155 } 00156 00157 nodes.remove(node.id); 00158 }*/ 00159 } 00160 00161 /* 00162 * For pre-order iteration of a tree. 00163 */ 00164 class DoubleLinkedTreeIterator implements Iterator { 00165 00166 protected Stack nodesOnRight; 00167 00168 protected DoubleLinkedTreeNode nextNode; 00169 00170 00171 public DoubleLinkedTreeIterator(DoubleLinkedTreeNode startNode) { 00172 nextNode = startNode; 00173 nodesOnRight = new Stack(); 00174 } 00175 00176 public boolean hasNext() { 00177 return (nextNode != null); 00178 } 00179 00180 public Object next() { 00181 assert(hasNext()); 00182 00183 Object result = nextNode; 00184 00185 List children = nextNode.getChildren(); 00186 if (children.size() == 0) { // no children? Take node on top of stack, if stack not empty 00187 if (nodesOnRight.empty()) nextNode = null; 00188 else nextNode = (DoubleLinkedTreeNode)nodesOnRight.pop(); 00189 00190 } else { // there are children: the next node is the topleft child, the children on right are pushed on stack 00191 DoubleLinkedTreeNode firstChild = (DoubleLinkedTreeNode)children.get(0); 00192 nextNode = firstChild; 00193 00194 for (int iChildren = 1; iChildren < children.size(); ++iChildren) { 00195 Object childOnRight = children.get(iChildren); 00196 nodesOnRight.push(childOnRight); 00197 } 00198 } 00199 00200 return result; 00201 } 00202 00203 public void remove() { 00204 throw new UnsupportedOperationException("DoubleLinkedTreeIterator does not provide a \"remove()\" method."); 00205 } 00206 00207 }