diff options
author | Vincent Ambo <mail@tazj.in> | 2021-12-13T22·51+0300 |
---|---|---|
committer | Vincent Ambo <mail@tazj.in> | 2021-12-13T23·15+0300 |
commit | 019f8fd2113df4c5247c3969c60fd4f0e08f91f7 (patch) | |
tree | 76a857f61aa88f62a30e854651e8439db77fd0ea /users/wpcarro/scratch/data_structures_and_algorithms/second-largest-item-bst.py | |
parent | 464bbcb15c09813172c79820bcf526bb10cf4208 (diff) | |
parent | 6123e976928ca3d8d93f0b2006b10b5f659eb74d (diff) |
subtree(users/wpcarro): docking briefcase at '24f5a642' r/3226
git-subtree-dir: users/wpcarro git-subtree-mainline: 464bbcb15c09813172c79820bcf526bb10cf4208 git-subtree-split: 24f5a642af3aa1627bbff977f0a101907a02c69f Change-Id: I6105b3762b79126b3488359c95978cadb3efa789
Diffstat (limited to 'users/wpcarro/scratch/data_structures_and_algorithms/second-largest-item-bst.py')
-rw-r--r-- | users/wpcarro/scratch/data_structures_and_algorithms/second-largest-item-bst.py | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/users/wpcarro/scratch/data_structures_and_algorithms/second-largest-item-bst.py b/users/wpcarro/scratch/data_structures_and_algorithms/second-largest-item-bst.py new file mode 100644 index 000000000000..bc167d975a7b --- /dev/null +++ b/users/wpcarro/scratch/data_structures_and_algorithms/second-largest-item-bst.py @@ -0,0 +1,179 @@ +import unittest +from collections import deque + + +################################################################################ +# Implementation +################################################################################ +def is_leaf(node): + return node.left is None and node.right is None + + +def find_largest(node): + current = node + while current.right is not None: + current = current.right + return current.value + + +def find_second_largest(node): + history = deque() + current = node + + while current.right: + history.append(current) + current = current.right + + if current.left: + return find_largest(current.left) + elif history: + return history.pop().value + else: + raise TypeError + + +def find_second_largest_backup(node): + history = deque() + current = node + + # traverse -> largest + while current.right: + history.append(current) + current = current.right + + if current.left: + return find_largest(current.left) + elif history: + return history.pop().value + else: + raise ArgumentError + + +# Write a iterative version to avoid consuming memory with the call stack. +# Commenting out the recursive code for now. +def find_second_largest_backup(node): + if node.left is None and node.right is None: + raise ArgumentError + + elif node.right is None and is_leaf(node.left): + return node.left.value + + # recursion + # elif node.right is None: + # return find_largest(node.left) + + # iterative version + elif node.right is None: + current = node.left + while current.right is not None: + current = current.right + return current.value + + # recursion + # TODO: Remove recursion from here. + elif not is_leaf(node.right): + return find_second_largest(node.right) + + # could do an else here, but let's be more assertive. + elif is_leaf(node.right): + return node.value + + else: + raise ArgumentError + + +################################################################################ +# Tests +################################################################################ +class Test(unittest.TestCase): + class BinaryTreeNode(object): + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + def insert_left(self, value): + self.left = Test.BinaryTreeNode(value) + return self.left + + def insert_right(self, value): + self.right = Test.BinaryTreeNode(value) + return self.right + + def test_full_tree(self): + tree = Test.BinaryTreeNode(50) + left = tree.insert_left(30) + right = tree.insert_right(70) + left.insert_left(10) + left.insert_right(40) + right.insert_left(60) + right.insert_right(80) + actual = find_second_largest(tree) + expected = 70 + self.assertEqual(actual, expected) + + def test_largest_has_a_left_child(self): + tree = Test.BinaryTreeNode(50) + left = tree.insert_left(30) + right = tree.insert_right(70) + left.insert_left(10) + left.insert_right(40) + right.insert_left(60) + actual = find_second_largest(tree) + expected = 60 + self.assertEqual(actual, expected) + + def test_largest_has_a_left_subtree(self): + tree = Test.BinaryTreeNode(50) + left = tree.insert_left(30) + right = tree.insert_right(70) + left.insert_left(10) + left.insert_right(40) + right_left = right.insert_left(60) + right_left_left = right_left.insert_left(55) + right_left.insert_right(65) + right_left_left.insert_right(58) + actual = find_second_largest(tree) + expected = 65 + self.assertEqual(actual, expected) + + def test_second_largest_is_root_node(self): + tree = Test.BinaryTreeNode(50) + left = tree.insert_left(30) + tree.insert_right(70) + left.insert_left(10) + left.insert_right(40) + actual = find_second_largest(tree) + expected = 50 + self.assertEqual(actual, expected) + + def test_descending_linked_list(self): + tree = Test.BinaryTreeNode(50) + left = tree.insert_left(40) + left_left = left.insert_left(30) + left_left_left = left_left.insert_left(20) + left_left_left.insert_left(10) + actual = find_second_largest(tree) + expected = 40 + self.assertEqual(actual, expected) + + def test_ascending_linked_list(self): + tree = Test.BinaryTreeNode(50) + right = tree.insert_right(60) + right_right = right.insert_right(70) + right_right.insert_right(80) + actual = find_second_largest(tree) + expected = 70 + self.assertEqual(actual, expected) + + def test_error_when_tree_has_one_node(self): + tree = Test.BinaryTreeNode(50) + with self.assertRaises(Exception): + find_second_largest(tree) + + def test_error_when_tree_is_empty(self): + with self.assertRaises(Exception): + find_second_largest(None) + + +unittest.main(verbosity=2) |