/** * Set up the threads with the help of extreme nodes. A node is "extreme" when it is the * leftmost/rightmost in the lowest level. * * <p>1. work out left and right subtree 2. get extreme nodes from the left and right subtree 3. * calculate the offset from parent & set a new thread if required * * @return the leftmost and the rightmost node on the deepest level of the subtree rooted at this * node */ private NodePair<BSTNode> RTPreposition() { NodePair<BSTNode> result = new NodePair<BSTNode>(); NodePair<BSTNode> fromLeftSubtree = null, fromRightSubtree = null; offset = 0; // 1. & 2. work out left & right subtree if (getLeft() != null) fromLeftSubtree = getLeft().RTPreposition(); if (getRight() != null) fromRightSubtree = getRight().RTPreposition(); // 3. examine this node if (isLeaf()) { if (!isRoot()) { offset = isLeft() ? -DataStructure.minsepx / 2 : +DataStructure.minsepx / 2; } result.left = this; result.right = this; } else { // This is not a leaf; at least one subtree is non-empty. /* * If one subtree is empty, it is not necessary to make a new * thread. A proper offset must be set. */ if (getLeft() == null) { getRight().offset = DataStructure.minsepx / 2; result.left = fromRightSubtree.left; result.right = fromRightSubtree.right; return result; } if (getRight() == null) { getLeft().offset = -DataStructure.minsepx / 2; result.left = fromLeftSubtree.left; result.right = fromLeftSubtree.right; return result; } // Calculate offsets for the left and the right son. int loffset = 0; // offset of this node from the right contour of // the left subtree. int roffset = 0; // offset of this node from the left contour of the // right subtree. BSTNode L = getLeft(); BSTNode R = getRight(); /* * First, left.offset is 0 and only right.offset accumulates. The * offsets are corrected afterwards (this way is easier to * generalize to m-ary trees). Note that offsets can be negative. */ getLeft().offset = 0; getRight().offset = 0; // traverse the right contour of the left subtree and the left // counour of the right subtree while ((L != null) && (R != null)) { /* * left.offset + loffset is the horizontal distance from L to * this node. Similarly, right.offset + roffset is the * horizontal distance from R to this node. */ int distance = (loffset + DataStructure.minsepx - roffset); if (distance > 0) { getRight().offset += distance; roffset += distance; } /* * When passes through thread there will be for sure incorrect * offset! So Elevator calculate this new offset. In algorithm * TR published by Reingold this value is already calculated. */ boolean LwasThread = L.thread, RwasThread = R.thread; L = (L.right != null) ? L.right : L.left; if (L != null) { loffset += L.offset; } R = (R.left != null) ? R.left : R.right; if (R != null) { roffset += R.offset; } BSTNode Elevator = null; if (LwasThread) { LwasThread = false; loffset = 0; Elevator = L; while (Elevator != this) { loffset += Elevator.offset; Elevator = Elevator.getParent(); } } if (RwasThread) { roffset = 0; Elevator = R; while (Elevator != this) { roffset += Elevator.offset; Elevator = Elevator.getParent(); } } } /* * Now, distances should be 0 for left and some value for right.. So * lets change it */ getRight().offset /= 2; getLeft().offset = -getRight().offset; /* * General switch of making a new thread: we want to make a thread * iff one pair of extremes is deeper than others. We assume that * threads from subtrees are set properly. */ if ((R != null) && (L == null)) { // the right subtree is deeper // than the left subtree fromLeftSubtree.left.thread = true; fromLeftSubtree.left.right = R; result.left = fromRightSubtree.left; result.right = fromRightSubtree.right; } else if ((L != null) && (R == null)) { // the left subtree is // deeper than the right // subtree fromRightSubtree.right.thread = true; fromRightSubtree.right.left = L; result.left = fromLeftSubtree.left; result.right = fromLeftSubtree.right; } else if ((L == null) && (R == null)) { // both subtrees have the // same height result.left = fromLeftSubtree.left; result.right = fromRightSubtree.right; } } return result; }