/* * Copyright (C) 2012 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.common.collect; import com.google.caliper.BeforeExperiment; import com.google.caliper.Benchmark; import com.google.caliper.Param; import com.google.common.base.Optional; import com.google.common.primitives.Ints; import java.util.List; import java.util.Random; /** * Benchmarks for the {@code TreeTraverser} operations on binary trees. * * @author Louis Wasserman */ public class BinaryTreeTraverserBenchmark { private static class BinaryNode { final int x; final Optional left; final Optional right; BinaryNode(int x, Optional left, Optional right) { this.x = x; this.left = left; this.right = right; } } enum Topology { BALANCED { @Override Optional createTree(int size, Random rng) { if (size == 0) { return Optional.absent(); } else { int leftChildSize = (size - 1) / 2; int rightChildSize = size - 1 - leftChildSize; return Optional.of( new BinaryNode( rng.nextInt(), createTree(leftChildSize, rng), createTree(rightChildSize, rng))); } } }, ALL_LEFT { @Override Optional createTree(int size, Random rng) { Optional root = Optional.absent(); for (int i = 0; i < size; i++) { root = Optional.of(new BinaryNode(rng.nextInt(), root, Optional.absent())); } return root; } }, ALL_RIGHT { @Override Optional createTree(int size, Random rng) { Optional root = Optional.absent(); for (int i = 0; i < size; i++) { root = Optional.of(new BinaryNode(rng.nextInt(), Optional.absent(), root)); } return root; } }, RANDOM { /** * Generates a tree with topology selected uniformly at random from the topologies of binary * trees of the specified size. */ @Override Optional createTree(int size, Random rng) { int[] keys = new int[size]; for (int i = 0; i < size; i++) { keys[i] = rng.nextInt(); } return createTreap(Ints.asList(keys)); } // See http://en.wikipedia.org/wiki/Treap for details on the algorithm. private Optional createTreap(List keys) { if (keys.isEmpty()) { return Optional.absent(); } int minIndex = 0; for (int i = 1; i < keys.size(); i++) { if (keys.get(i) < keys.get(minIndex)) { minIndex = i; } } Optional leftChild = createTreap(keys.subList(0, minIndex)); Optional rightChild = createTreap(keys.subList(minIndex + 1, keys.size())); return Optional.of(new BinaryNode(keys.get(minIndex), leftChild, rightChild)); } }; abstract Optional createTree(int size, Random rng); } private static final TreeTraverser VIEWER = new TreeTraverser() { @Override public Iterable children(BinaryNode root) { return Optional.presentInstances(ImmutableList.of(root.left, root.right)); } }; enum Traversal { PRE_ORDER { @Override Iterable view(T root, TreeTraverser viewer) { return viewer.preOrderTraversal(root); } }, POST_ORDER { @Override Iterable view(T root, TreeTraverser viewer) { return viewer.postOrderTraversal(root); } }, BREADTH_FIRST { @Override Iterable view(T root, TreeTraverser viewer) { return viewer.breadthFirstTraversal(root); } }; abstract Iterable view(T root, TreeTraverser viewer); } private Iterable view; @Param Topology topology; @Param({"1", "100", "10000", "1000000"}) int size; @Param Traversal traversal; @Param({"1234"}) SpecialRandom rng; @BeforeExperiment void setUp() { this.view = traversal.view(topology.createTree(size, rng).get(), VIEWER); } @Benchmark int traversal(int reps) { int tmp = 0; for (int i = 0; i < reps; i++) { for (BinaryNode node : view) { tmp += node.x; } } return tmp; } }