第12章 高级数据结构及其实现
自顶向下伸展树
1 // SplayTree class 2 // 3 // CONSTRUCTION: with no initializer 4 // 5 // ******************PUBLIC OPERATIONS********************* 6 // void insert( x ) --> Insert x 7 // void remove( x ) --> Remove x 8 // boolean contains( x ) --> Return true if x is found 9 // Comparable findMin( ) --> Return smallest item 10 // Comparable findMax( ) --> Return largest item 11 // boolean isEmpty( ) --> Return true if empty; else false 12 // void makeEmpty( ) --> Remove all items 13 // ******************ERRORS******************************** 14 // Throws UnderflowException as appropriate 15 16 /** 17 * Implements a top-down splay tree. 18 * Note that all "matching" is based on the compareTo method. 19 * @author Mark Allen Weiss 20 */ 21 public class SplayTree<AnyType extends Comparable<? super AnyType>> 22 { 23 /** 24 * Construct the tree. 25 */ 26 public SplayTree( ) 27 { 28 nullNode = new BinaryNode<AnyType>( null ); 29 nullNode.left = nullNode.right = nullNode; 30 root = nullNode; 31 } 32 33 private BinaryNode<AnyType> newNode = null; // Used between different inserts 34 35 /** 36 * Insert into the tree. 37 * @param x the item to insert. 38 */ 39 public void insert( AnyType x ) 40 { 41 if( newNode == null ) 42 newNode = new BinaryNode<AnyType>( null ); 43 newNode.element = x; 44 45 if( root == nullNode ) 46 { 47 newNode.left = newNode.right = nullNode; 48 root = newNode; 49 } 50 else 51 { 52 root = splay( x, root ); 53 54 int compareResult = x.compareTo( root.element ); 55 56 if( compareResult < 0 ) 57 { 58 newNode.left = root.left; 59 newNode.right = root; 60 root.left = nullNode; 61 root = newNode; 62 } 63 else 64 if( compareResult > 0 ) 65 { 66 newNode.right = root.right; 67 newNode.left = root; 68 root.right = nullNode; 69 root = newNode; 70 } 71 else 72 return; // No duplicates 73 } 74 newNode = null; // So next insert will call new 75 } 76 77 /** 78 * Remove from the tree. 79 * @param x the item to remove. 80 */ 81 public void remove( AnyType x ) 82 { 83 if( !contains( x ) ) 84 return; 85 86 BinaryNode<AnyType> newTree; 87 88 // If x is found, it will be splayed to the root by contains 89 if( root.left == nullNode ) 90 newTree = root.right; 91 else 92 { 93 // Find the maximum in the left subtree 94 // Splay it to the root; and then attach right child 95 newTree = root.left; 96 newTree = splay( x, newTree ); 97 newTree.right = root.right; 98 } 99 root = newTree; 100 } 101 102 /** 103 * Find the smallest item in the tree. 104 * Not the most efficient implementation (uses two passes), but has correct 105 * amortized behavior. 106 * A good alternative is to first call find with parameter 107 * smaller than any item in the tree, then call findMin. 108 * @return the smallest item or throw UnderflowException if empty. 109 */ 110 public AnyType findMin( ) 111 { 112 if( isEmpty( ) ) 113 throw new UnderflowException( ); 114 115 BinaryNode<AnyType> ptr = root; 116 117 while( ptr.left != nullNode ) 118 ptr = ptr.left; 119 120 root = splay( ptr.element, root ); 121 return ptr.element; 122 } 123 124 /** 125 * Find the largest item in the tree. 126 * Not the most efficient implementation (uses two passes), but has correct 127 * amortized behavior. 128 * A good alternative is to first call find with parameter 129 * larger than any item in the tree, then call findMax. 130 * @return the largest item or throw UnderflowException if empty. 131 */ 132 public AnyType findMax( ) 133 { 134 if( isEmpty( ) ) 135 throw new UnderflowException( ); 136 137 BinaryNode<AnyType> ptr = root; 138 139 while( ptr.right != nullNode ) 140 ptr = ptr.right; 141 142 root = splay( ptr.element, root ); 143 return ptr.element; 144 } 145 146 /** 147 * Find an item in the tree. 148 * @param x the item to search for. 149 * @return true if x is found; otherwise false. 150 */ 151 public boolean contains( AnyType x ) 152 { 153 if( isEmpty( ) ) 154 return false; 155 156 root = splay( x, root ); 157 158 return root.element.compareTo( x ) == 0; 159 } 160 161 /** 162 * Make the tree logically empty. 163 */ 164 public void makeEmpty( ) 165 { 166 root = nullNode; 167 } 168 169 /** 170 * Test if the tree is logically empty. 171 * @return true if empty, false otherwise. 172 */ 173 public boolean isEmpty( ) 174 { 175 return root == nullNode; 176 } 177 178 private BinaryNode<AnyType> header = new BinaryNode<AnyType>( null ); // For splay 179 180 /** 181 * Internal method to perform a top-down splay. 182 * The last accessed node becomes the new root. 183 * @param x the target item to splay around. 184 * @param t the root of the subtree to splay. 185 * @return the subtree after the splay. 186 */ 187 private BinaryNode<AnyType> splay( AnyType x, BinaryNode<AnyType> t ) 188 { 189 BinaryNode<AnyType> leftTreeMax, rightTreeMin; 190 191 header.left = header.right = nullNode; 192 leftTreeMax = rightTreeMin = header; 193 194 nullNode.element = x; // Guarantee a match 195 196 for( ; ; ) 197 { 198 int compareResult = x.compareTo( t.element ); 199 200 if( compareResult < 0 ) 201 { 202 if( x.compareTo( t.left.element ) < 0 ) 203 t = rotateWithLeftChild( t ); 204 if( t.left == nullNode ) 205 break; 206 // Link Right 207 rightTreeMin.left = t; 208 rightTreeMin = t; 209 t = t.left; 210 } 211 else if( compareResult > 0 ) 212 { 213 if( x.compareTo( t.right.element ) > 0 ) 214 t = rotateWithRightChild( t ); 215 if( t.right == nullNode ) 216 break; 217 // Link Left 218 leftTreeMax.right = t; 219 leftTreeMax = t; 220 t = t.right; 221 } 222 else 223 break; 224 } 225 226 leftTreeMax.right = t.left; 227 rightTreeMin.left = t.right; 228 t.left = header.right; 229 t.right = header.left; 230 return t; 231 } 232 233 /** 234 * Rotate binary tree node with left child. 235 * For AVL trees, this is a single rotation for case 1. 236 */ 237 private static <AnyType> BinaryNode<AnyType> rotateWithLeftChild( BinaryNode<AnyType> k2 ) 238 { 239 BinaryNode<AnyType> k1 = k2.left; 240 k2.left = k1.right; 241 k1.right = k2; 242 return k1; 243 } 244 245 /** 246 * Rotate binary tree node with right child. 247 * For AVL trees, this is a single rotation for case 4. 248 */ 249 private static <AnyType> BinaryNode<AnyType> rotateWithRightChild( BinaryNode<AnyType> k1 ) 250 { 251 BinaryNode<AnyType> k2 = k1.right; 252 k1.right = k2.left; 253 k2.left = k1; 254 return k2; 255 } 256 257 // Basic node stored in unbalanced binary search trees 258 private static class BinaryNode<AnyType> 259 { 260 // Constructors 261 BinaryNode( AnyType theElement ) 262 { 263 this( theElement, null, null ); 264 } 265 266 BinaryNode( AnyType theElement, BinaryNode<AnyType> lt, BinaryNode<AnyType> rt ) 267 { 268 element = theElement; 269 left = lt; 270 right = rt; 271 } 272 273 AnyType element; // The data in the node 274 BinaryNode<AnyType> left; // Left child 275 BinaryNode<AnyType> right; // Right child 276 } 277 278 private BinaryNode<AnyType> root; 279 private BinaryNode<AnyType> nullNode; 280 281 282 // Test program; should print min and max and nothing else 283 public static void main( String [ ] args ) 284 { 285 SplayTree<Integer> t = new SplayTree<Integer>( ); 286 final int NUMS = 40000; 287 final int GAP = 307; 288 289 System.out.println( "Checking... (no bad output means success)" ); 290 291 for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS ) 292 t.insert( i ); 293 System.out.println( "Inserts complete" ); 294 295 for( int i = 1; i < NUMS; i += 2 ) 296 t.remove( i ); 297 System.out.println( "Removes complete" ); 298 299 if( t.findMin( ) != 2 || t.findMax( ) != NUMS - 2 ) 300 System.out.println( "FindMin or FindMax error!" ); 301 302 for( int i = 2; i < NUMS; i += 2 ) 303 if( !t.contains( i ) ) 304 System.out.println( "Error: find fails for " + i ); 305 306 for( int i = 1; i < NUMS; i += 2 ) 307 if( t.contains( i ) ) 308 System.out.println( "Error: Found deleted item " + i ); 309 } 310 }
红黑树
1 // RedBlackTree class 2 // 3 // CONSTRUCTION: with no parameters 4 // 5 // ******************PUBLIC OPERATIONS********************* 6 // void insert( x ) --> Insert x 7 // void remove( x ) --> Remove x (unimplemented) 8 // boolean contains( x ) --> Return true if x is found 9 // Comparable findMin( ) --> Return smallest item 10 // Comparable findMax( ) --> Return largest item 11 // boolean isEmpty( ) --> Return true if empty; else false 12 // void makeEmpty( ) --> Remove all items 13 // void printTree( ) --> Print all items 14 // ******************ERRORS******************************** 15 // Throws UnderflowException as appropriate 16 17 /** 18 * Implements a red-black tree. 19 * Note that all "matching" is based on the compareTo method. 20 * @author Mark Allen Weiss 21 */ 22 public class RedBlackTree<AnyType extends Comparable<? super AnyType>> 23 { 24 /** 25 * Construct the tree. 26 */ 27 public RedBlackTree( ) 28 { 29 nullNode = new RedBlackNode<>( null ); 30 nullNode.left = nullNode.right = nullNode; 31 header = new RedBlackNode<>( null ); 32 header.left = header.right = nullNode; 33 } 34 35 /** 36 * Compare item and t.element, using compareTo, with 37 * caveat that if t is header, then item is always larger. 38 * This routine is called if is possible that t is header. 39 * If it is not possible for t to be header, use compareTo directly. 40 */ 41 private int compare( AnyType item, RedBlackNode<AnyType> t ) 42 { 43 if( t == header ) 44 return 1; 45 else 46 return item.compareTo( t.element ); 47 } 48 49 /** 50 * Insert into the tree. 51 * @param item the item to insert. 52 */ 53 public void insert( AnyType item ) 54 { 55 current = parent = grand = header; 56 nullNode.element = item; 57 58 while( compare( item, current ) != 0 ) 59 { 60 great = grand; grand = parent; parent = current; 61 current = compare( item, current ) < 0 ? 62 current.left : current.right; 63 64 // Check if two red children; fix if so 65 if( current.left.color == RED && current.right.color == RED ) 66 handleReorient( item ); 67 } 68 69 // Insertion fails if already present 70 if( current != nullNode ) 71 return; 72 current = new RedBlackNode<>( item, nullNode, nullNode ); 73 74 // Attach to parent 75 if( compare( item, parent ) < 0 ) 76 parent.left = current; 77 else 78 parent.right = current; 79 handleReorient( item ); 80 } 81 82 /** 83 * Remove from the tree. 84 * @param x the item to remove. 85 * @throws UnsupportedOperationException if called. 86 */ 87 public void remove( AnyType x ) 88 { 89 throw new UnsupportedOperationException( ); 90 } 91 92 /** 93 * Find the smallest item the tree. 94 * @return the smallest item or throw UnderflowExcepton if empty. 95 */ 96 public AnyType findMin( ) 97 { 98 if( isEmpty( ) ) 99 throw new UnderflowException( ); 100 101 RedBlackNode<AnyType> itr = header.right; 102 103 while( itr.left != nullNode ) 104 itr = itr.left; 105 106 return itr.element; 107 } 108 109 /** 110 * Find the largest item in the tree. 111 * @return the largest item or throw UnderflowExcepton if empty. 112 */ 113 public AnyType findMax( ) 114 { 115 if( isEmpty( ) ) 116 throw new UnderflowException( ); 117 118 RedBlackNode<AnyType> itr = header.right; 119 120 while( itr.right != nullNode ) 121 itr = itr.right; 122 123 return itr.element; 124 } 125 126 /** 127 * Find an item in the tree. 128 * @param x the item to search for. 129 * @return true if x is found; otherwise false. 130 */ 131 public boolean contains( AnyType x ) 132 { 133 nullNode.element = x; 134 current = header.right; 135 136 for( ; ; ) 137 { 138 if( x.compareTo( current.element ) < 0 ) 139 current = current.left; 140 else if( x.compareTo( current.element ) > 0 ) 141 current = current.right; 142 else if( current != nullNode ) 143 return true; 144 else 145 return false; 146 } 147 } 148 149 /** 150 * Make the tree logically empty. 151 */ 152 public void makeEmpty( ) 153 { 154 header.right = nullNode; 155 } 156 157 /** 158 * Print the tree contents in sorted order. 159 */ 160 public void printTree( ) 161 { 162 if( isEmpty( ) ) 163 System.out.println( "Empty tree" ); 164 else 165 printTree( header.right ); 166 } 167 168 /** 169 * Internal method to print a subtree in sorted order. 170 * @param t the node that roots the subtree. 171 */ 172 private void printTree( RedBlackNode<AnyType> t ) 173 { 174 if( t != nullNode ) 175 { 176 printTree( t.left ); 177 System.out.println( t.element ); 178 printTree( t.right ); 179 } 180 } 181 182 /** 183 * Test if the tree is logically empty. 184 * @return true if empty, false otherwise. 185 */ 186 public boolean isEmpty( ) 187 { 188 return header.right == nullNode; 189 } 190 191 /** 192 * Internal routine that is called during an insertion 193 * if a node has two red children. Performs flip and rotations. 194 * @param item the item being inserted. 195 */ 196 private void handleReorient( AnyType item ) 197 { 198 // Do the color flip 199 current.color = RED; 200 current.left.color = BLACK; 201 current.right.color = BLACK; 202 203 if( parent.color == RED ) // Have to rotate 204 { 205 grand.color = RED; 206 if( ( compare( item, grand ) < 0 ) != 207 ( compare( item, parent ) < 0 ) ) 208 parent = rotate( item, grand ); // Start dbl rotate 209 current = rotate( item, great ); 210 current.color = BLACK; 211 } 212 header.right.color = BLACK; // Make root black 213 } 214 215 /** 216 * Internal routine that performs a single or double rotation. 217 * Because the result is attached to the parent, there are four cases. 218 * Called by handleReorient. 219 * @param item the item in handleReorient. 220 * @param parent the parent of the root of the rotated subtree. 221 * @return the root of the rotated subtree. 222 */ 223 private RedBlackNode<AnyType> rotate( AnyType item, RedBlackNode<AnyType> parent ) 224 { 225 if( compare( item, parent ) < 0 ) 226 return parent.left = compare( item, parent.left ) < 0 ? 227 rotateWithLeftChild( parent.left ) : // LL 228 rotateWithRightChild( parent.left ) ; // LR 229 else 230 return parent.right = compare( item, parent.right ) < 0 ? 231 rotateWithLeftChild( parent.right ) : // RL 232 rotateWithRightChild( parent.right ); // RR 233 } 234 235 /** 236 * Rotate binary tree node with left child. 237 */ 238 private RedBlackNode<AnyType> rotateWithLeftChild( RedBlackNode<AnyType> k2 ) 239 { 240 RedBlackNode<AnyType> k1 = k2.left; 241 k2.left = k1.right; 242 k1.right = k2; 243 return k1; 244 } 245 246 /** 247 * Rotate binary tree node with right child. 248 */ 249 private RedBlackNode<AnyType> rotateWithRightChild( RedBlackNode<AnyType> k1 ) 250 { 251 RedBlackNode<AnyType> k2 = k1.right; 252 k1.right = k2.left; 253 k2.left = k1; 254 return k2; 255 } 256 257 private static class RedBlackNode<AnyType> 258 { 259 // Constructors 260 RedBlackNode( AnyType theElement ) 261 { 262 this( theElement, null, null ); 263 } 264 265 RedBlackNode( AnyType theElement, RedBlackNode<AnyType> lt, RedBlackNode<AnyType> rt ) 266 { 267 element = theElement; 268 left = lt; 269 right = rt; 270 color = RedBlackTree.BLACK; 271 } 272 273 AnyType element; // The data in the node 274 RedBlackNode<AnyType> left; // Left child 275 RedBlackNode<AnyType> right; // Right child 276 int color; // Color 277 } 278 279 private RedBlackNode<AnyType> header; 280 private RedBlackNode<AnyType> nullNode; 281 282 private static final int BLACK = 1; // BLACK must be 1 283 private static final int RED = 0; 284 285 // Used in insert routine and its helpers 286 private RedBlackNode<AnyType> current; 287 private RedBlackNode<AnyType> parent; 288 private RedBlackNode<AnyType> grand; 289 private RedBlackNode<AnyType> great; 290 291 292 // Test program 293 public static void main( String [ ] args ) 294 { 295 RedBlackTree<Integer> t = new RedBlackTree<>( ); 296 final int NUMS = 400000; 297 final int GAP = 35461; 298 299 System.out.println( "Checking... (no more output means success)" ); 300 301 for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS ) 302 t.insert( i ); 303 304 if( t.findMin( ) != 1 || t.findMax( ) != NUMS - 1 ) 305 System.out.println( "FindMin or FindMax error!" ); 306 307 for( int i = 1; i < NUMS; i++ ) 308 if( !t.contains( i ) ) 309 System.out.println( "Find error1!" ); 310 } 311 }
Treap树
1 // Treap class 2 // 3 // CONSTRUCTION: with no initializer 4 // 5 // ******************PUBLIC OPERATIONS********************* 6 // void insert( x ) --> Insert x 7 // void remove( x ) --> Remove x 8 // boolean contains( x ) --> Return true if x is found 9 // Comparable findMin( ) --> Return smallest item 10 // Comparable findMax( ) --> Return largest item 11 // boolean isEmpty( ) --> Return true if empty; else false 12 // void makeEmpty( ) --> Remove all items 13 // void printTree( ) --> Print tree in sorted order 14 // ******************ERRORS******************************** 15 // Throws UnderflowException as appropriate 16 17 /** 18 * Implements a treap. 19 * Note that all "matching" is based on the compareTo method. 20 * @author Mark Allen Weiss 21 */ 22 public class Treap<AnyType extends Comparable<? super AnyType>> 23 { 24 /** 25 * Construct the treap. 26 */ 27 public Treap( ) 28 { 29 nullNode = new TreapNode<>( null ); 30 nullNode.left = nullNode.right = nullNode; 31 nullNode.priority = Integer.MAX_VALUE; 32 root = nullNode; 33 } 34 35 /** 36 * Insert into the tree. Does nothing if x is already present. 37 * @param x the item to insert. 38 */ 39 public void insert( AnyType x ) 40 { 41 root = insert( x, root ); 42 } 43 44 /** 45 * Remove from the tree. Does nothing if x is not found. 46 * @param x the item to remove. 47 */ 48 public void remove( AnyType x ) 49 { 50 root = remove( x, root ); 51 } 52 53 /** 54 * Find the smallest item in the tree. 55 * @return the smallest item, or throw UnderflowException if empty. 56 */ 57 public AnyType findMin( ) 58 { 59 if( isEmpty( ) ) 60 throw new UnderflowException( ); 61 62 TreapNode<AnyType> ptr = root; 63 64 while( ptr.left != nullNode ) 65 ptr = ptr.left; 66 67 return ptr.element; 68 } 69 70 /** 71 * Find the largest item in the tree. 72 * @return the largest item, or throw UnderflowException if empty. 73 */ 74 public AnyType findMax( ) 75 { 76 if( isEmpty( ) ) 77 throw new UnderflowException( ); 78 79 TreapNode<AnyType> ptr = root; 80 81 while( ptr.right != nullNode ) 82 ptr = ptr.right; 83 84 return ptr.element; 85 } 86 87 /** 88 * Find an item in the tree. 89 * @param x the item to search for. 90 * @return true if x is found. 91 */ 92 public boolean contains( AnyType x ) 93 { 94 TreapNode<AnyType> current = root; 95 nullNode.element = x; 96 97 for( ; ; ) 98 { 99 int compareResult = x.compareTo( current.element ); 100 101 if( compareResult < 0 ) 102 current = current.left; 103 else if( compareResult > 0 ) 104 current = current.right; 105 else 106 return current != nullNode; 107 } 108 } 109 110 /** 111 * Make the tree logically empty. 112 */ 113 public void makeEmpty( ) 114 { 115 root = nullNode; 116 } 117 118 /** 119 * Test if the tree is logically empty. 120 * @return true if empty, false otherwise. 121 */ 122 public boolean isEmpty( ) 123 { 124 return root == nullNode; 125 } 126 127 /** 128 * Print the tree contents in sorted order. 129 */ 130 public void printTree( ) 131 { 132 if( isEmpty( ) ) 133 System.out.println( "Empty tree" ); 134 else 135 printTree( root ); 136 } 137 138 /** 139 * Internal method to insert into a subtree. 140 * @param x the item to insert. 141 * @param t the node that roots the subtree. 142 * @return the new root of the subtree. 143 */ 144 private TreapNode<AnyType> insert( AnyType x, TreapNode<AnyType> t ) 145 { 146 if( t == nullNode ) 147 return new TreapNode<>( x, nullNode, nullNode ); 148 149 int compareResult = x.compareTo( t.element ); 150 151 if( compareResult < 0 ) 152 { 153 t.left = insert( x, t.left ); 154 if( t.left.priority < t.priority ) 155 t = rotateWithLeftChild( t ); 156 } 157 else if( compareResult > 0 ) 158 { 159 t.right = insert( x, t.right ); 160 if( t.right.priority < t.priority ) 161 t = rotateWithRightChild( t ); 162 } 163 // Otherwise, it's a duplicate; do nothing 164 165 return t; 166 } 167 168 /** 169 * Internal method to remove from a subtree. 170 * @param x the item to remove. 171 * @param t the node that roots the subtree. 172 * @return the new root of the subtree. 173 */ 174 private TreapNode<AnyType> remove( AnyType x, TreapNode<AnyType> t ) 175 { 176 if( t != nullNode ) 177 { 178 int compareResult = x.compareTo( t.element ); 179 180 if( compareResult < 0 ) 181 t.left = remove( x, t.left ); 182 else if( compareResult > 0 ) 183 t.right = remove( x, t.right ); 184 else 185 { 186 // Match found 187 if( t.left.priority < t.right.priority ) 188 t = rotateWithLeftChild( t ); 189 else 190 t = rotateWithRightChild( t ); 191 192 if( t != nullNode ) // Continue on down 193 t = remove( x, t ); 194 else 195 t.left = nullNode; // At a leaf 196 } 197 } 198 return t; 199 } 200 201 /** 202 * Internal method to print a subtree in sorted order. 203 * @param t the node that roots the tree. 204 */ 205 private void printTree( TreapNode<AnyType> t ) 206 { 207 if( t != t.left ) 208 { 209 printTree( t.left ); 210 System.out.println( t.element.toString( ) ); 211 printTree( t.right ); 212 } 213 } 214 215 /** 216 * Rotate binary tree node with left child. 217 */ 218 private TreapNode<AnyType> rotateWithLeftChild( TreapNode<AnyType> k2 ) 219 { 220 TreapNode<AnyType> k1 = k2.left; 221 k2.left = k1.right; 222 k1.right = k2; 223 return k1; 224 } 225 226 /** 227 * Rotate binary tree node with right child. 228 */ 229 private TreapNode<AnyType> rotateWithRightChild( TreapNode<AnyType> k1 ) 230 { 231 TreapNode<AnyType> k2 = k1.right; 232 k1.right = k2.left; 233 k2.left = k1; 234 return k2; 235 } 236 237 private static class TreapNode<AnyType> 238 { 239 // Constructors 240 TreapNode( AnyType theElement ) 241 { 242 this( theElement, null, null ); 243 } 244 245 TreapNode( AnyType theElement, TreapNode<AnyType> lt, TreapNode<AnyType> rt ) 246 { 247 element = theElement; 248 left = lt; 249 right = rt; 250 priority = randomObj.randomInt( ); 251 } 252 253 // Friendly data; accessible by other package routines 254 AnyType element; // The data in the node 255 TreapNode<AnyType> left; // Left child 256 TreapNode<AnyType> right; // Right child 257 int priority; // Priority 258 259 private static Random randomObj = new Random( ); 260 } 261 262 private TreapNode<AnyType> root; 263 private TreapNode<AnyType> nullNode; 264 265 266 // Test program 267 public static void main( String [ ] args ) 268 { 269 Treap<Integer> t = new Treap<>( ); 270 final int NUMS = 40000; 271 final int GAP = 307; 272 273 System.out.println( "Checking... (no bad output means success)" ); 274 275 for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS ) 276 t.insert( i ); 277 System.out.println( "Inserts complete" ); 278 279 for( int i = 1; i < NUMS; i+= 2 ) 280 t.remove( i ); 281 System.out.println( "Removes complete" ); 282 283 if( NUMS < 40 ) 284 t.printTree( ); 285 if( t.findMin( ) != 2 || t.findMax( ) != NUMS - 2 ) 286 System.out.println( "FindMin or FindMax error!" ); 287 288 for( int i = 2; i < NUMS; i+=2 ) 289 if( !t.contains( i ) ) 290 System.out.println( "Error: find fails for " + i ); 291 292 for( int i = 1; i < NUMS; i+=2 ) 293 if( t.contains( i ) ) 294 System.out.println( "Error: Found deleted item " + i ); 295 } 296 }
后缀树
后缀树的一小部分应用列举如下:
1. 找到T中最长的重复子串:遍历树,找到带最大字母深度的内部节点,这就表示了最大的LCP。运行时间是O(|T|)。好可以推广到重复了至少k遍的最长子串。
2. 找到两个字符串T1和T2的最长公共子串:合成一个字符串T1#T2,其中#是不在任一字符串的某个字符。然后为这个字符串建立后缀树,找到最深的那个内部节点,其至少存在一个后缀是在#之前起始的,一个是在#之后起始的。这个完成时间可以做到跟字符串的总长度成正比,并且推广为解决总长度为N的k个字符串问题的O(kN)算法。
3. 找到模式P出现的次数:假设后缀树增加了记录,简单地沿着内部节点向下的路径,使每个叶子保持跟踪其下面的后缀的个数;第一个是P的前缀的内部节点提供了答案;如果这样的节点不存在,答案是0和1,可以通过检查搜索终止处的后缀得到。这个花费的时间跟模式P的长度成正比,而与|T|的大小无关。
4. 找到指定长度L > 1的最常见子串:返回那些字母深度至少为L的节点中规模最大的内部节点。所花时间是O(|T|)。
1 import java.util.Arrays; 2 3 class SuffixArray 4 { 5 6 /* 7 * Create the LCP array from the suffix array 8 * @param s the input array populated from 0..N-1, with available pos N 9 * @param sa the already-computed suffix array 0..N-1 10 * @param LCP the resulting LCP array 0..N-1 11 */ 12 public static void makeLCPArray( int [ ] s, int [ ] sa, int [ ] LCP ) 13 { 14 int N = sa.length; 15 int [ ] rank = new int[ N ]; 16 17 s[ N ] = -1; 18 for( int i = 0; i < N; i++ ) 19 rank[ sa[ i ] ] = i; 20 21 int h = 0; 22 for( int i = 0; i < N; i++ ) 23 if( rank[ i ] > 0 ) 24 { 25 int j = sa[ rank[ i ] - 1 ]; 26 27 while( s[ i + h ] == s[ j + h ] ) 28 h++; 29 30 LCP[ rank[ i ] ] = h; 31 if( h > 0 ) 32 h--; 33 } 34 } 35 36 /* 37 * Fill in the suffix array information for String str 38 * @param str the input String 39 * @param sa existing array to place the suffix array 40 */ 41 public static void createSuffixArray( String str, int [ ] sa, int [ ] LCP ) 42 { 43 int N = str.length( ); 44 45 int [ ] s = new int[ N + 3 ]; 46 int [ ] SA = new int[ N + 3 ]; 47 48 for( int i = 0; i < N; i++ ) 49 s[ i ] = str.charAt( i ); 50 51 makeSuffixArray( s, SA, N, 256 ); 52 53 for( int i = 0; i < N; i++ ) 54 sa[ i ] = SA[ i ]; 55 56 makeLCPArray( s, sa, LCP ); 57 } 58 59 60 // find the suffix array SA of s[0..n-1] in {1..K}^n 61 // require s[n]=s[n+1]=s[n+2]=0, n>=2 62 public static void makeSuffixArray( int [ ] s, int [ ] SA, int n, int K ) 63 { 64 int n0 = ( n + 2 ) / 3; 65 int n1 = ( n + 1 ) / 3; 66 int n2 = n / 3; 67 int t = n0 - n1; // 1 iff n%3 == 1 68 int n12 = n1 + n2 + t; 69 70 int [ ] s12 = new int[ n12 + 3 ]; 71 int [ ] SA12 = new int[ n12 + 3 ]; 72 int [ ] s0 = new int[ n0 ]; 73 int [ ] SA0 = new int[ n0 ]; 74 75 // generate positions in s for items in s12 76 // the "+t" adds a dummy mod 1 suffix if n%3 == 1 77 // at that point, the size of s12 is n12 78 for( int i = 0, j = 0; i < n + t; i++ ) 79 if( i % 3 != 0 ) 80 s12[ j++ ] = i; 81 82 int K12 = assignNames( s, s12, SA12, n0, n12, K ); 83 84 computeS12( s12, SA12, n12, K12 ); 85 computeS0( s, s0, SA0, SA12, n0, n12, K ); 86 merge( s, s12, SA, SA0, SA12, n, n0, n12, t ); 87 } 88 89 // Assigns the new supercharacter names. 90 // At end of routine, SA will have indices into s, in sorted order 91 // and s12 will have new character names 92 // Returns the number of names assigned; note that if 93 // this value is the same as n12, then SA is a suffix array for s12. 94 private static int assignNames( int [ ] s, int [ ] s12, int [ ] SA12, 95 int n0, int n12, int K ) 96 { 97 // radix sort the new character trios 98 radixPass( s12 , SA12, s, 2, n12, K ); 99 radixPass( SA12, s12 , s, 1, n12, K ); 100 radixPass( s12 , SA12, s, 0, n12, K ); 101 102 // find lexicographic names of triples 103 int name = 0; 104 int c0 = -1, c1 = -1, c2 = -1; 105 106 for( int i = 0; i < n12; i++ ) 107 { 108 if( s[ SA12[ i ] ] != c0 || s[ SA12[ i ] + 1 ] != c1 109 || s[ SA12[ i ] + 2 ] != c2 ) 110 { 111 name++; 112 c0 = s[ SA12[ i ] ]; 113 c1 = s[ SA12[ i ] + 1 ]; 114 c2 = s[ SA12[ i ] + 2 ]; 115 } 116 117 if( SA12[ i ] % 3 == 1 ) 118 s12[ SA12[ i ] / 3 ] = name; 119 else 120 s12[ SA12[ i ] / 3 + n0 ] = name; 121 } 122 123 return name; 124 } 125 126 127 // stably sort in[0..n-1] with indices into s that has keys in 0..K 128 // into out[0..n-1]; sort is relative to offset into s 129 // uses counting radix sort 130 private static void radixPass( int [ ] in, int [ ] out, int [ ] s, int offset, 131 int n, int K ) 132 { 133 int [ ] count = new int[ K + 2 ]; // counter array 134 135 for( int i = 0; i < n; i++ ) 136 count[ s[ in[ i ] + offset ] + 1 ]++; // count occurences 137 138 for( int i = 1; i <= K + 1; i++ ) // compute exclusive sums 139 count[ i ] += count[ i - 1 ]; 140 141 for( int i = 0; i < n; i++ ) 142 out[ count[ s[ in[ i ] + offset ] ]++ ] = in[ i ]; // sort 143 } 144 145 // stably sort in[0..n-1] with indices into s that has keys in 0..K 146 // into out[0..n-1] 147 // uses counting radix sort 148 private static void radixPass( int [ ] in, int [ ] out, int [ ] s, int n, int K ) 149 { 150 radixPass( in, out, s, 0, n, K ); 151 } 152 153 154 // Compute the suffix array for s12, placing result into SA12 155 private static void computeS12( int [ ] s12, int [ ] SA12, int n12, int K12 ) 156 { 157 if( K12 == n12 ) // if unique names, don't need recursion 158 for( int i = 0; i < n12; i++ ) 159 SA12[ s12[i] - 1 ] = i; 160 else 161 { 162 makeSuffixArray( s12, SA12, n12, K12 ); 163 // store unique names in s12 using the suffix array 164 for( int i = 0; i < n12; i++ ) 165 s12[ SA12[ i ] ] = i + 1; 166 } 167 } 168 169 private static void computeS0( int [ ] s, int [ ] s0, int [ ] SA0, int [ ] SA12, 170 int n0, int n12, int K ) 171 { 172 for( int i = 0, j = 0; i < n12; i++ ) 173 if( SA12[ i ] < n0 ) 174 s0[ j++ ] = 3 * SA12[ i ]; 175 176 radixPass( s0, SA0, s, n0, K ); 177 } 178 179 180 // merge sorted SA0 suffixes and sorted SA12 suffixes 181 private static void merge( int [ ] s, int [ ] s12, 182 int [ ] SA, int [ ] SA0, int [ ] SA12, 183 int n, int n0, int n12, int t ) 184 { 185 int p = 0, k = 0; 186 187 while( t != n12 && p != n0 ) 188 { 189 int i = getIndexIntoS( SA12, t, n0 ); // S12 190 int j = SA0[ p ]; // S0 191 192 if( suffix12IsSmaller( s, s12, SA12, n0, i, j, t ) ) 193 { 194 SA[ k++ ] = i; 195 t++; 196 } 197 else 198 { 199 SA[ k++ ] = j; 200 p++; 201 } 202 } 203 204 while( p < n0 ) 205 SA[ k++ ] = SA0[ p++ ]; 206 while( t < n12 ) 207 SA[ k++ ] = getIndexIntoS( SA12, t++, n0 ); 208 } 209 210 private static int getIndexIntoS( int [ ] SA12, int t, int n0 ) 211 { 212 if( SA12[ t ] < n0 ) 213 return SA12[ t ] * 3 + 1; 214 else 215 return ( SA12[ t ] - n0 ) * 3 + 2; 216 } 217 218 private static boolean leq( int a1, int a2, int b1, int b2 ) 219 { return a1 < b1 || a1 == b1 && a2 <= b2; } 220 221 private static boolean leq( int a1, int a2, int a3, int b1, int b2, int b3 ) 222 { return a1 < b1 || a1 == b1 && leq( a2, a3,b2, b3 ); } 223 224 private static boolean suffix12IsSmaller( int [ ] s, int [ ] s12, int [ ] SA12, 225 int n0, int i, int j, int t ) 226 { 227 if( SA12[ t ] < n0 ) // s1 vs s0; can break tie after 1 character 228 return leq( s[ i ], s12[ SA12[ t ] + n0 ], 229 s[ j ], s12[ j / 3 ] ); 230 else // s2 vs s0; can break tie after 2 characters 231 return leq( s[ i ], s[ i + 1 ], s12[ SA12[ t ] - n0 + 1 ], 232 s[ j ], s[ j + 1 ], s12[ j / 3 + n0 ] ); 233 } 234 235 public static void printV( int [ ] a, String comment ) 236 { 237 System.out.print( comment + ":" ); 238 for( int x : a ) 239 System.out.print( x + " " ); 240 241 System.out.println( ); 242 } 243 244 public static boolean isPermutation( int [ ] SA, int n ) 245 { 246 boolean [ ] seen = new boolean [ n ]; 247 248 for( int i = 0; i < n; i++ ) 249 seen[ i ] = false; 250 251 for( int i = 0; i < n; i++ ) 252 seen[ SA[ i ] ] = true; 253 254 for( int i = 0; i < n; i++ ) 255 if( !seen[ i ] ) 256 return false; 257 258 return true; 259 } 260 261 public static boolean sleq( int [ ] s1, int start1, int [ ] s2, int start2 ) 262 { 263 for( int i = start1, j = start2; ; i++, j++ ) 264 { 265 if( s1[ i ] < s2[ j ] ) 266 return true; 267 268 if( s1[ i ] > s2[ j ] ) 269 return false; 270 } 271 } 272 273 // Check if SA is a sorted suffix array for s 274 public static boolean isSorted( int [ ] SA, int [ ] s, int n ) 275 { 276 for( int i = 0; i < n-1; i++ ) 277 if( !sleq( s, SA[ i ], s, SA[ i + 1 ] ) ) 278 return false; 279 280 return true; 281 } 282 283 284 285 public static void assert0( boolean cond ) 286 { 287 if( !cond ) 288 throw new AssertionException( ); 289 } 290 291 292 public static void test( String str ) 293 { 294 int [ ] sufarr = new int[ str.length( ) ]; 295 int [ ] LCP = new int[ str.length( ) ]; 296 297 createSuffixArray( str, sufarr, LCP ); 298 299 System.out.println( str + ":" ); 300 for( int i = 0; i < str.length( ); i++ ) 301 System.out.println( i + " " + sufarr[ i ] + " " + LCP[ i ] ); 302 System.out.println( ); 303 } 304 305 public static void main( String [ ] args ) 306 { 307 test( "banana" ); 308 test( "aaaaaa" ); 309 } 310 311 /* 312 * Returns the LCP for any two strings 313 */ 314 public static int computeLCP( String s1, String s2 ) 315 { 316 int i = 0; 317 318 while( i < s1.length( ) && i < s2.length( ) && s1.charAt( i ) == s2.charAt( i ) ) 319 i++; 320 321 return i; 322 } 323 324 /* 325 * Fill in the suffix array and LCP information for String str 326 * @param str the input String 327 * @param SA existing array to place the suffix array 328 * @param LCP existing array to place the LCP information 329 * Note: Starting in Java 7, this will use quadratic space. 330 */ 331 public static void createSuffixArraySlow( String str, int [ ] SA, int [ ] LCP ) 332 { 333 if( SA.length != str.length( ) || LCP.length != str.length( ) ) 334 throw new IllegalArgumentException( ); 335 336 int N = str.length( ); 337 338 String [ ] suffixes = new String[ N ]; 339 for( int i = 0; i < N; i++ ) 340 suffixes[ i ] = str.substring( i ); 341 342 Arrays.sort( suffixes ); 343 344 for( int i = 0; i < N; i++ ) 345 SA[ i ] = N - suffixes[ i ].length( ); 346 347 LCP[ 0 ] = 0; 348 for( int i = 1; i < N; i++ ) 349 LCP[ i ] = computeLCP( suffixes[ i - 1 ], suffixes[ i ] ); 350 } 351 } 352 353 354 class AssertionException extends RuntimeException 355 { 356 }
k - d树
1 /** 2 * Quick illustration of a two-dimensional tree. 3 */ 4 public class KdTree<AnyType extends Comparable<? super AnyType>> 5 { 6 private static class KdNode<AnyType> 7 { 8 AnyType [ ] data; 9 KdNode<AnyType> left; 10 KdNode<AnyType> right; 11 12 KdNode( AnyType item[ ] ) 13 { 14 data = (AnyType[]) new Comparable[ 2 ]; 15 data[ 0 ] = item[ 0 ]; 16 data[ 1 ] = item[ 1 ]; 17 left = right = null; 18 } 19 } 20 21 private KdNode<AnyType> root; 22 23 public KdTree( ) 24 { 25 root = null; 26 } 27 28 public void insert( AnyType [ ] x ) 29 { 30 root = insert( x, root, 0 ); 31 } 32 33 private KdNode<AnyType> insert( AnyType [ ] x, KdNode<AnyType> t, int level ) 34 { 35 if( t == null ) 36 t = new KdNode<>( x ); 37 else if( x[ level ].compareTo( t.data[ level ] ) < 0 ) 38 t.left = insert( x, t.left, 1 - level ); 39 else 40 t.right = insert( x, t.right, 1 - level ); 41 return t; 42 } 43 44 /** 45 * Print items satisfying 46 * low[ 0 ] <= x[ 0 ] <= high[ 0 ] and 47 * low[ 1 ] <= x[ 1 ] <= high[ 1 ]. 48 */ 49 public void printRange( AnyType [ ] low, AnyType [ ] high ) 50 { 51 printRange( low, high, root, 0 ); 52 } 53 54 private void printRange( AnyType [ ] low, AnyType [ ] high, 55 KdNode<AnyType> t, int level ) 56 { 57 if( t != null ) 58 { 59 if( low[ 0 ].compareTo( t.data[ 0 ] ) <= 0 && 60 low[ 1 ].compareTo( t.data[ 1 ] ) <= 0 && 61 high[ 0 ].compareTo( t.data[ 0 ] ) >= 0 && 62 high[ 1 ].compareTo( t.data[ 1 ] ) >= 0 ) 63 System.out.println( "(" + t.data[ 0 ] + "," 64 + t.data[ 1 ] + ")" ); 65 66 if( low[ level ].compareTo( t.data[ level ] ) <= 0 ) 67 printRange( low, high, t.left, 1 - level ); 68 if( high[ level ].compareTo( t.data[ level ] ) >= 0 ) 69 printRange( low, high, t.right, 1 - level ); 70 } 71 } 72 73 public static void main( String [ ] args ) 74 { 75 KdTree<Integer> t = new KdTree<>( ); 76 77 System.out.println( "Starting program" ); 78 for( int i = 300; i < 370; i++ ) 79 { 80 Integer [ ] it = new Integer[ 2 ]; 81 it[ 0 ] = i; 82 it[ 1 ] = 2500 - i; 83 t.insert( it ); 84 } 85 86 Integer [ ] low = { 70, 2186 }; 87 Integer [ ] high = { 1200, 2200 }; 88 89 t.printRange( low, high ); 90 } 91 }
配对堆
1 import java.util.ArrayList; 2 3 // PairingHeap class 4 // 5 // CONSTRUCTION: with no initializer 6 // 7 // ******************PUBLIC OPERATIONS********************* 8 // Position insert( x ) --> Insert x, return position 9 // Comparable deleteMin( )--> Return and remove smallest item 10 // Comparable findMin( ) --> Return smallest item 11 // boolean isEmpty( ) --> Return true if empty; else false 12 // int size( ) --> Return size of priority queue 13 // void makeEmpty( ) --> Remove all items 14 // void decreaseKey( Position p, newVal ) 15 // --> Decrease value in node p 16 // ******************ERRORS******************************** 17 // Exceptions thrown for various operations 18 19 /** 20 * Implements a pairing heap. 21 * Supports a decreaseKey operation. 22 * Note that all "matching" is based on the compareTo method. 23 * @author Mark Allen Weiss 24 * @see PriorityQueue.Position 25 */ 26 public class PairingHeap<AnyType extends Comparable<? super AnyType>> 27 { 28 /** 29 * The Position interface represents a type that can 30 * be used for the decreaseKey operation. 31 */ 32 public interface Position<AnyType> 33 { 34 /** 35 * Returns the value stored at this position. 36 * @return the value stored at this position. 37 */ 38 AnyType getValue( ); 39 } 40 41 /** 42 * Construct the pairing heap. 43 */ 44 public PairingHeap( ) 45 { 46 root = null; 47 theSize = 0; 48 } 49 50 /** 51 * Insert into the priority queue, and return a Position 52 * that can be used by decreaseKey. 53 * Duplicates are allowed. 54 * @param x the item to insert. 55 * @return the node containing the newly inserted item. 56 */ 57 public Position<AnyType> insert( AnyType x ) 58 { 59 PairNode<AnyType> newNode = new PairNode<>( x ); 60 61 if( root == null ) 62 root = newNode; 63 else 64 root = compareAndLink( root, newNode ); 65 66 theSize++; 67 return newNode; 68 } 69 70 /** 71 * Find the smallest item in the priority queue. 72 * @return the smallest item. 73 * @throws UnderflowException if pairing heap is empty. 74 */ 75 public AnyType findMin( ) 76 { 77 if( isEmpty( ) ) 78 throw new UnderflowException( ); 79 return root.element; 80 } 81 82 /** 83 * Remove the smallest item from the priority queue. 84 * @return the smallest item. 85 * @throws UnderflowException if pairing heap is empty. 86 */ 87 public AnyType deleteMin( ) 88 { 89 if( isEmpty( ) ) 90 throw new UnderflowException( ); 91 92 AnyType x = findMin( ); 93 root.element = null; // null it out in case used in decreaseKey 94 if( root.leftChild == null ) 95 root = null; 96 else 97 root = combineSiblings( root.leftChild ); 98 99 theSize--; 100 return x; 101 } 102 103 /** 104 * Change the value of the item stored in the pairing heap. 105 * @param pos any Position returned by insert. 106 * @param newVal the new value, which must be smaller 107 * than the currently stored value. 108 * @throws IllegalArgumentException if pos is null. 109 * @throws IllegalArgumentException if new value is larger than old. 110 */ 111 public void decreaseKey( Position<AnyType> pos, AnyType newVal ) 112 { 113 if( pos == null ) 114 throw new IllegalArgumentException( "null Position passed to decreaseKey" ); 115 116 PairNode<AnyType> p = (PairNode<AnyType>) pos; 117 118 if( p.element == null ) 119 throw new IllegalArgumentException( "pos already deleted" ); 120 if( p.element.compareTo( newVal ) < 0 ) 121 throw new IllegalArgumentException( "newVal/oldval: " + newVal + " /" + p.element ); 122 p.element = newVal; 123 if( p != root ) 124 { 125 if( p.nextSibling != null ) 126 p.nextSibling.prev = p.prev; 127 if( p.prev.leftChild == p ) 128 p.prev.leftChild = p.nextSibling; 129 else 130 p.prev.nextSibling = p.nextSibling; 131 132 p.nextSibling = null; 133 root = compareAndLink( root, p ); 134 } 135 } 136 137 /** 138 * Test if the priority queue is logically empty. 139 * @return true if empty, false otherwise. 140 */ 141 public boolean isEmpty( ) 142 { 143 return root == null; 144 } 145 146 /** 147 * Returns number of items stored in the priority queue. 148 * @return size of the priority queue. 149 */ 150 public int size( ) 151 { 152 return theSize; 153 } 154 155 /** 156 * Make the priority queue logically empty. 157 */ 158 public void makeEmpty( ) 159 { 160 root = null; 161 theSize = 0; 162 } 163 164 /** 165 * Private static class for use with PairingHeap. 166 */ 167 private static class PairNode<AnyType> implements Position<AnyType> 168 { 169 /** 170 * Construct the PairNode. 171 * @param theElement the value stored in the node. 172 */ 173 public PairNode( AnyType theElement ) 174 { 175 element = theElement; 176 leftChild = null; 177 nextSibling = null; 178 prev = null; 179 } 180 181 /** 182 * Returns the value stored at this position. 183 * @return the value stored at this position. 184 */ 185 public AnyType getValue( ) 186 { 187 return element; 188 } 189 190 // Friendly data; accessible by other package routines 191 public AnyType element; 192 public PairNode<AnyType> leftChild; 193 public PairNode<AnyType> nextSibling; 194 public PairNode<AnyType> prev; 195 } 196 197 private PairNode<AnyType> root; 198 private int theSize; 199 200 /** 201 * Internal method that is the basic operation to maintain order. 202 * Links first and second together to satisfy heap order. 203 * @param first root of tree 1, which may not be null. 204 * first.nextSibling MUST be null on entry. 205 * @param second root of tree 2, which may be null. 206 * @return result of the tree merge. 207 */ 208 private PairNode<AnyType> compareAndLink( PairNode<AnyType> first, PairNode<AnyType> second ) 209 { 210 if( second == null ) 211 return first; 212 213 if( second.element.compareTo( first.element ) < 0 ) 214 { 215 // Attach first as leftmost child of second 216 second.prev = first.prev; 217 first.prev = second; 218 first.nextSibling = second.leftChild; 219 if( first.nextSibling != null ) 220 first.nextSibling.prev = first; 221 second.leftChild = first; 222 return second; 223 } 224 else 225 { 226 // Attach second as leftmost child of first 227 second.prev = first; 228 first.nextSibling = second.nextSibling; 229 if( first.nextSibling != null ) 230 first.nextSibling.prev = first; 231 second.nextSibling = first.leftChild; 232 if( second.nextSibling != null ) 233 second.nextSibling.prev = second; 234 first.leftChild = second; 235 return first; 236 } 237 } 238 239 private PairNode<AnyType> [ ] doubleIfFull( PairNode<AnyType> [ ] array, int index ) 240 { 241 if( index == array.length ) 242 { 243 PairNode<AnyType> [ ] oldArray = array; 244 245 array = new PairNode[ index * 2 ]; 246 for( int i = 0; i < index; i++ ) 247 array[ i ] = oldArray[ i ]; 248 } 249 return array; 250 } 251 252 // The tree array for combineSiblings 253 private PairNode<AnyType> [ ] treeArray = new PairNode[ 5 ]; 254 255 /** 256 * Internal method that implements two-pass merging. 257 * @param firstSibling the root of the conglomerate; 258 * assumed not null. 259 */ 260 private PairNode<AnyType> combineSiblings( PairNode<AnyType> firstSibling ) 261 { 262 if( firstSibling.nextSibling == null ) 263 return firstSibling; 264 265 // Store the subtrees in an array 266 int numSiblings = 0; 267 for( ; firstSibling != null; numSiblings++ ) 268 { 269 treeArray = doubleIfFull( treeArray, numSiblings ); 270 treeArray[ numSiblings ] = firstSibling; 271 firstSibling.prev.nextSibling = null; // break links 272 firstSibling = firstSibling.nextSibling; 273 } 274 treeArray = doubleIfFull( treeArray, numSiblings ); 275 treeArray[ numSiblings ] = null; 276 277 // Combine subtrees two at a time, going left to right 278 int i = 0; 279 for( ; i + 1 < numSiblings; i += 2 ) 280 treeArray[ i ] = compareAndLink( treeArray[ i ], treeArray[ i + 1 ] ); 281 282 // j has the result of last compareAndLink. 283 // If an odd number of trees, get the last one. 284 int j = i - 2; 285 if( j == numSiblings - 3 ) 286 treeArray[ j ] = compareAndLink( treeArray[ j ], treeArray[ j + 2 ] ); 287 288 // Now go right to left, merging last tree with 289 // next to last. The result becomes the new last. 290 for( ; j >= 2; j -= 2 ) 291 treeArray[ j - 2 ] = compareAndLink( treeArray[ j - 2 ], treeArray[ j ] ); 292 293 return (PairNode<AnyType>) treeArray[ 0 ]; 294 } 295 296 // Test program 297 public static void main( String [ ] args ) 298 { 299 PairingHeap<Integer> h = new PairingHeap<>( ); 300 int numItems = 10000; 301 int i = 37; 302 int j; 303 304 System.out.println( "Checking; no bad output is good" ); 305 for( i = 37; i != 0; i = ( i + 37 ) % numItems ) 306 h.insert( i ); 307 for( i = 1; i < numItems; i++ ) 308 if( h.deleteMin( ) != i ) 309 System.out.println( "Oops! " + i ); 310 311 ArrayList<PairingHeap.Position<Integer>> p = new ArrayList<>( ); 312 for( i = 0; i < numItems; i++ ) 313 p.add( null ); 314 315 for( i = 0, j = numItems / 2; i < numItems; i++, j =(j+71)%numItems ) 316 p.set( j, h.insert( j + numItems ) ); 317 for( i = 0, j = numItems / 2; i < numItems; i++, j =(j+53)%numItems ) 318 h.decreaseKey( p.get( j ), p.get( j ).getValue( ) - numItems ); 319 i = -1; 320 while( !h.isEmpty( ) ) 321 if( h.deleteMin( ) != ++i ) 322 System.out.println( "Oops! " + i + " " ); 323 System.out.println( "Check completed" ); 324 } 325 }