| // Copyright 2007 The Closure Library Authors. All Rights Reserved. |
| // |
| // 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. |
| |
| goog.provide('goog.structs.AvlTreeTest'); |
| goog.setTestOnly('goog.structs.AvlTreeTest'); |
| |
| goog.require('goog.array'); |
| goog.require('goog.structs.AvlTree'); |
| goog.require('goog.testing.jsunit'); |
| |
| |
| /** |
| * This test verifies that we can insert strings into the AvlTree and have |
| * them be stored and sorted correctly by the default comparator. |
| */ |
| function testInsertsWithDefaultComparator() { |
| var tree = new goog.structs.AvlTree(); |
| var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; |
| |
| // Insert strings into tree out of order |
| tree.add(values[4]); |
| tree.add(values[3]); |
| tree.add(values[0]); |
| tree.add(values[6]); |
| tree.add(values[5]); |
| tree.add(values[1]); |
| tree.add(values[2]); |
| |
| // Verify strings are stored in sorted order |
| var i = 0; |
| tree.inOrderTraverse(function(value) { |
| assertEquals(values[i], value); |
| i += 1; |
| }); |
| assertEquals(i, values.length); |
| |
| // Verify that no nodes are visited if the start value is larger than all |
| // values |
| tree.inOrderTraverse(function(value) { |
| fail(); |
| }, 'zed'); |
| |
| // Verify strings are stored in sorted order |
| i = values.length; |
| tree.reverseOrderTraverse(function(value) { |
| i--; |
| assertEquals(values[i], value); |
| }); |
| assertEquals(i, 0); |
| |
| // Verify that no nodes are visited if the start value is smaller than all |
| // values |
| tree.reverseOrderTraverse(function(value) { |
| fail(); |
| }, 'aardvark'); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert strings into and remove strings from |
| * the AvlTree and have the only the non-removed values be stored and sorted |
| * correctly by the default comparator. |
| */ |
| function testRemovesWithDefaultComparator() { |
| var tree = new goog.structs.AvlTree(); |
| var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; |
| |
| // Insert strings into tree out of order |
| tree.add('frodo'); |
| tree.add(values[4]); |
| tree.add(values[3]); |
| tree.add(values[0]); |
| tree.add(values[6]); |
| tree.add('samwise'); |
| tree.add(values[5]); |
| tree.add(values[1]); |
| tree.add(values[2]); |
| tree.add('pippin'); |
| |
| // Remove strings from tree |
| assertEquals(tree.remove('samwise'), 'samwise'); |
| assertEquals(tree.remove('pippin'), 'pippin'); |
| assertEquals(tree.remove('frodo'), 'frodo'); |
| assertEquals(tree.remove('merry'), null); |
| |
| |
| // Verify strings are stored in sorted order |
| var i = 0; |
| tree.inOrderTraverse(function(value) { |
| assertEquals(values[i], value); |
| i += 1; |
| }); |
| assertEquals(i, values.length); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert values into and remove values from |
| * the AvlTree and have them be stored and sorted correctly by a custom |
| * comparator. |
| */ |
| function testInsertsAndRemovesWithCustomComparator() { |
| var tree = new goog.structs.AvlTree(function(a, b) { |
| return a - b; |
| }); |
| |
| var NUM_TO_INSERT = 37; |
| var valuesToRemove = [1, 0, 6, 7, 36]; |
| |
| // Insert ints into tree out of order |
| var values = []; |
| for (var i = 0; i < NUM_TO_INSERT; i += 1) { |
| tree.add(i); |
| values.push(i); |
| } |
| |
| for (var i = 0; i < valuesToRemove.length; i += 1) { |
| assertEquals(tree.remove(valuesToRemove[i]), valuesToRemove[i]); |
| goog.array.remove(values, valuesToRemove[i]); |
| } |
| assertEquals(tree.remove(-1), null); |
| assertEquals(tree.remove(37), null); |
| |
| // Verify strings are stored in sorted order |
| var i = 0; |
| tree.inOrderTraverse(function(value) { |
| assertEquals(values[i], value); |
| i += 1; |
| }); |
| assertEquals(i, values.length); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert values into and remove values from |
| * the AvlTree and have it maintain the AVL-Tree upperbound on its height. |
| */ |
| function testAvlTreeHeight() { |
| var tree = new goog.structs.AvlTree(function(a, b) { |
| return a - b; |
| }); |
| |
| var NUM_TO_INSERT = 2000; |
| var NUM_TO_REMOVE = 500; |
| |
| // Insert ints into tree out of order |
| for (var i = 0; i < NUM_TO_INSERT; i += 1) { |
| tree.add(i); |
| } |
| |
| // Remove valuse |
| for (var i = 0; i < NUM_TO_REMOVE; i += 1) { |
| tree.remove(i); |
| } |
| |
| assertTrue(tree.getHeight() <= 1.4405 * |
| (Math.log(NUM_TO_INSERT - NUM_TO_REMOVE + 2) / Math.log(2)) - 1.3277); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert values into and remove values from |
| * the AvlTree and have its contains method correctly determine the values it |
| * is contains. |
| */ |
| function testAvlTreeContains() { |
| var tree = new goog.structs.AvlTree(); |
| var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; |
| |
| // Insert strings into tree out of order |
| tree.add('frodo'); |
| tree.add(values[4]); |
| tree.add(values[3]); |
| tree.add(values[0]); |
| tree.add(values[6]); |
| tree.add('samwise'); |
| tree.add(values[5]); |
| tree.add(values[1]); |
| tree.add(values[2]); |
| tree.add('pippin'); |
| |
| // Remove strings from tree |
| assertEquals(tree.remove('samwise'), 'samwise'); |
| assertEquals(tree.remove('pippin'), 'pippin'); |
| assertEquals(tree.remove('frodo'), 'frodo'); |
| |
| for (var i = 0; i < values.length; i += 1) { |
| assertTrue(tree.contains(values[i])); |
| } |
| assertFalse(tree.contains('samwise')); |
| assertFalse(tree.contains('pippin')); |
| assertFalse(tree.contains('frodo')); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert values into and remove values from |
| * the AvlTree and have its indexOf method correctly determine the in-order |
| * index of the values it contains. |
| */ |
| function testAvlTreeIndexOf() { |
| var tree = new goog.structs.AvlTree(); |
| var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; |
| |
| // Insert strings into tree out of order |
| tree.add('frodo'); |
| tree.add(values[4]); |
| tree.add(values[3]); |
| tree.add(values[0]); |
| tree.add(values[6]); |
| tree.add('samwise'); |
| tree.add(values[5]); |
| tree.add(values[1]); |
| tree.add(values[2]); |
| tree.add('pippin'); |
| |
| // Remove strings from tree |
| assertEquals('samwise', tree.remove('samwise')); |
| assertEquals('pippin', tree.remove('pippin')); |
| assertEquals('frodo', tree.remove('frodo')); |
| |
| for (var i = 0; i < values.length; i += 1) { |
| assertEquals(i, tree.indexOf(values[i])); |
| } |
| assertEquals(-1, tree.indexOf('samwise')); |
| assertEquals(-1, tree.indexOf('pippin')); |
| assertEquals(-1, tree.indexOf('frodo')); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert values into and remove values from |
| * the AvlTree and have its minValue and maxValue routines return the correct |
| * min and max values contained by the tree. |
| */ |
| function testMinAndMaxValues() { |
| var tree = new goog.structs.AvlTree(function(a, b) { |
| return a - b; |
| }); |
| |
| var NUM_TO_INSERT = 2000; |
| var NUM_TO_REMOVE = 500; |
| |
| // Insert ints into tree out of order |
| for (var i = 0; i < NUM_TO_INSERT; i += 1) { |
| tree.add(i); |
| } |
| |
| // Remove valuse |
| for (var i = 0; i < NUM_TO_REMOVE; i += 1) { |
| tree.remove(i); |
| } |
| |
| assertEquals(tree.getMinimum(), NUM_TO_REMOVE); |
| assertEquals(tree.getMaximum(), NUM_TO_INSERT - 1); |
| } |
| |
| |
| /** |
| * This test verifies that we can insert values into and remove values from |
| * the AvlTree and traverse the tree in reverse order using the |
| * reverseOrderTraverse routine. |
| */ |
| function testReverseOrderTraverse() { |
| var tree = new goog.structs.AvlTree(function(a, b) { |
| return a - b; |
| }); |
| |
| var NUM_TO_INSERT = 2000; |
| var NUM_TO_REMOVE = 500; |
| |
| // Insert ints into tree out of order |
| for (var i = 0; i < NUM_TO_INSERT; i += 1) { |
| tree.add(i); |
| } |
| |
| // Remove valuse |
| for (var i = 0; i < NUM_TO_REMOVE; i += 1) { |
| tree.remove(i); |
| } |
| |
| var i = NUM_TO_INSERT - 1; |
| tree.reverseOrderTraverse(function(value) { |
| assertEquals(value, i); |
| i -= 1; |
| }); |
| assertEquals(i, NUM_TO_REMOVE - 1); |
| } |
| |
| |
| /** |
| * Verifies correct behavior of getCount(). See http://b/4347755 |
| */ |
| function testGetCountBehavior() { |
| var tree = new goog.structs.AvlTree(); |
| tree.add(1); |
| tree.remove(1); |
| assertEquals(0, tree.getCount()); |
| |
| var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; |
| |
| // Insert strings into tree out of order |
| tree.add('frodo'); |
| tree.add(values[4]); |
| tree.add(values[3]); |
| tree.add(values[0]); |
| tree.add(values[6]); |
| tree.add('samwise'); |
| tree.add(values[5]); |
| tree.add(values[1]); |
| tree.add(values[2]); |
| tree.add('pippin'); |
| assertEquals(10, tree.getCount()); |
| assertEquals( |
| tree.root_.left.count + tree.root_.right.count + 1, tree.getCount()); |
| |
| // Remove strings from tree |
| assertEquals('samwise', tree.remove('samwise')); |
| assertEquals('pippin', tree.remove('pippin')); |
| assertEquals('frodo', tree.remove('frodo')); |
| assertEquals(null, tree.remove('merry')); |
| assertEquals(7, tree.getCount()); |
| |
| assertEquals( |
| tree.root_.left.count + tree.root_.right.count + 1, tree.getCount()); |
| } |
| |
| |
| /** |
| * This test verifies that getKthOrder gets the correct value. |
| */ |
| function testGetKthOrder() { |
| var tree = new goog.structs.AvlTree(function(a, b) { |
| return a - b; |
| }); |
| |
| var NUM_TO_INSERT = 2000; |
| var NUM_TO_REMOVE = 500; |
| |
| // Insert ints into tree out of order |
| for (var i = 0; i < NUM_TO_INSERT; i += 1) { |
| tree.add(i); |
| } |
| |
| // Remove values. |
| for (var i = 0; i < NUM_TO_REMOVE; i += 1) { |
| tree.remove(i); |
| } |
| for (var k = 0; k < tree.getCount(); ++k) { |
| assertEquals(NUM_TO_REMOVE + k, tree.getKthValue(k)); |
| } |
| } |