1 /* 2 * Copyright (C) 2012 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.collect; 16 17 import com.google.caliper.BeforeExperiment; 18 import com.google.caliper.Benchmark; 19 import com.google.caliper.Param; 20 import com.google.common.base.Optional; 21 import com.google.common.primitives.Ints; 22 23 import java.util.List; 24 import java.util.Random; 25 26 /** 27 * Benchmarks for the {@code TreeTraverser} and optimized {@code BinaryTreeTraverser} operations on 28 * binary trees. 29 * 30 * @author Louis Wasserman 31 */ 32 public class BinaryTreeTraverserBenchmark { 33 private static class BinaryNode { 34 final int x; 35 final Optional<BinaryNode> left; 36 final Optional<BinaryNode> right; 37 38 BinaryNode(int x, Optional<BinaryNode> left, Optional<BinaryNode> right) { 39 this.x = x; 40 this.left = left; 41 this.right = right; 42 } 43 } 44 45 enum Topology { 46 BALANCED { 47 @Override 48 Optional<BinaryNode> createTree(int size, Random rng) { 49 if (size == 0) { 50 return Optional.absent(); 51 } else { 52 int leftChildSize = (size - 1) / 2; 53 int rightChildSize = size - 1 - leftChildSize; 54 return Optional.of(new BinaryNode( 55 rng.nextInt(), createTree(leftChildSize, rng), createTree(rightChildSize, rng))); 56 } 57 } 58 }, 59 ALL_LEFT { 60 @Override 61 Optional<BinaryNode> createTree(int size, Random rng) { 62 Optional<BinaryNode> root = Optional.absent(); 63 for (int i = 0; i < size; i++) { 64 root = Optional.of(new BinaryNode(rng.nextInt(), root, Optional.<BinaryNode>absent())); 65 } 66 return root; 67 } 68 }, 69 ALL_RIGHT { 70 @Override 71 Optional<BinaryNode> createTree(int size, Random rng) { 72 Optional<BinaryNode> root = Optional.absent(); 73 for (int i = 0; i < size; i++) { 74 root = Optional.of(new BinaryNode(rng.nextInt(), Optional.<BinaryNode>absent(), root)); 75 } 76 return root; 77 } 78 }, 79 RANDOM { 80 /** 81 * Generates a tree with topology selected uniformly at random from the topologies of binary 82 * trees of the specified size. 83 */ 84 @Override 85 Optional<BinaryNode> createTree(int size, Random rng) { 86 int[] keys = new int[size]; 87 for (int i = 0; i < size; i++) { 88 keys[i] = rng.nextInt(); 89 } 90 return createTreap(Ints.asList(keys)); 91 } 92 93 // See http://en.wikipedia.org/wiki/Treap for details on the algorithm. 94 private Optional<BinaryNode> createTreap(List<Integer> keys) { 95 if (keys.isEmpty()) { 96 return Optional.absent(); 97 } 98 int minIndex = 0; 99 for (int i = 1; i < keys.size(); i++) { 100 if (keys.get(i) < keys.get(minIndex)) { 101 minIndex = i; 102 } 103 } 104 Optional<BinaryNode> leftChild = createTreap(keys.subList(0, minIndex)); 105 Optional<BinaryNode> rightChild = createTreap(keys.subList(minIndex + 1, keys.size())); 106 return Optional.of(new BinaryNode(keys.get(minIndex), leftChild, rightChild)); 107 } 108 }; 109 110 abstract Optional<BinaryNode> createTree(int size, Random rng); 111 } 112 113 private static final BinaryTreeTraverser<BinaryNode> BINARY_VIEWER = 114 new BinaryTreeTraverser<BinaryNode>() { 115 116 @Override 117 public Optional<BinaryNode> leftChild(BinaryNode node) { 118 return node.left; 119 } 120 121 @Override 122 public Optional<BinaryNode> rightChild(BinaryNode node) { 123 return node.right; 124 } 125 }; 126 127 private static final TreeTraverser<BinaryNode> VIEWER = new TreeTraverser<BinaryNode>() { 128 @Override 129 public Iterable<BinaryNode> children(BinaryNode root) { 130 return BINARY_VIEWER.children(root); 131 } 132 }; 133 134 enum Traversal { 135 PRE_ORDER { 136 @Override 137 <T> Iterable<T> view(T root, TreeTraverser<T> viewer) { 138 return viewer.preOrderTraversal(root); 139 } 140 }, 141 POST_ORDER { 142 @Override 143 <T> Iterable<T> view(T root, TreeTraverser<T> viewer) { 144 return viewer.postOrderTraversal(root); 145 } 146 }, 147 BREADTH_FIRST { 148 @Override 149 <T> Iterable<T> view(T root, TreeTraverser<T> viewer) { 150 return viewer.breadthFirstTraversal(root); 151 } 152 }; 153 154 abstract <T> Iterable<T> view(T root, TreeTraverser<T> viewer); 155 } 156 157 private Iterable<BinaryNode> view; 158 159 @Param 160 Topology topology; 161 162 @Param({"1", "100", "10000", "1000000"}) 163 int size; 164 165 @Param 166 Traversal traversal; 167 168 @Param 169 boolean useBinaryTraverser; 170 171 @Param({"1234"}) 172 SpecialRandom rng; 173 174 @BeforeExperiment 175 void setUp() { 176 this.view = traversal.view( 177 topology.createTree(size, rng).get(), 178 useBinaryTraverser ? BINARY_VIEWER : VIEWER); 179 } 180 181 @Benchmark int traversal(int reps) { 182 int tmp = 0; 183 184 for (int i = 0; i < reps; i++) { 185 for (BinaryNode node : view) { 186 tmp += node.x; 187 } 188 } 189 return tmp; 190 } 191 } 192