Problem:
Binary Search Tree II

Write a program which performs the following operations to a binary search tree $T$ by adding the find operation to A: Binary Search Tree I.

insert $k$: Insert a node containing $k$ as key into $T$.

find $k$: Report whether $T$ has a node containing $k$.

print: Print the keys of the binary search tree by inorder tree walk and preorder tree walk respectively.

Input

In the first line, the number of operations $m$ is given. In the following $m$ lines, operations represented by insert $k$, find $k$ or print are given.

Output

For each find $k$ operation, print "yes" if $T$ has a node containing $k$, "no" if not.

In addition, for each print operation, print a list of keys obtained by inorder tree walk and preorder tree walk in a line respectively. Put a space character before each key.

Constraints

The number of operations $\leq 500,000$

The number of print operations $\leq 10$.

$-2,000,000,000 \leq key \leq 2,000,000,000$

The height of the binary tree does not exceed 100 if you employ the above pseudo code.

The keys in the binary search tree are all different.

Sample Input 1

10
insert 30
insert 88
insert 12
insert 1
insert 20
find 12
insert 17
insert 25
find 16
print

Sample Output 1

yes
no
1 12 17 20 25 30 88
30 12 1 20 17 25 88

Reference

Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

Solution in Scala (judge verdict: Accepted)

import scala.io.StdIn.{readInt, readLine};
import scala.annotation.tailrec;

object Main {
    def main(args: Array[String]): Unit = {
        val cnt = readInt;
        val binTree = new BinaryTree[Long,Boolean]((k1, k2) => if (k1 < k2) -1 else if (k1 > k2) 1 else 0);
        (0 until cnt).foreach { i =>
            readLine.split(" ") match {
                case Array("insert", key) => binTree.insert(key.toLong, true);
                case Array("find", key) => if (binTree.find(key.toLong) != None) println("yes") else println("no");
                case Array("delete", key) => binTree.delete(key.toLong);
                case Array("print") => {
                    println(" " + binTree.fetchInorder.map(_._1).mkString(" "));
                    println(" " + binTree.fetchPreoder.map(_._1).mkString(" "));
                }
            }
        }
    }
}
class BinaryTree[A,B](val compare: (A,A) => Int) {
    case class TreeNode(var key: Option[A], var value: Option[B], var parent: TreeNode, var left: TreeNode, var right: TreeNode);
    var tree: TreeNode = TreeNode(None, None, null, null, null);
    
    def isEmpty(): Boolean = if (tree.right == null) true else false;
    
    // 要素を登録する
    def insert(key: A, value: B): Unit = {
        @tailrec
        def _insert(parent: TreeNode, curr: TreeNode): Unit = {
            if (compare(key, curr.key.get) < 0) { // 追加対象ノードのほうが小さい
                if (curr.left == null) {
                    curr.left = TreeNode(Some(key), Some(value), parent, null, null);
                } else {
                    _insert(curr, curr.left);
                }
            } else if (compare(key, curr.key.get) > 0) { // 追加対象ノードのほうが大きい
                if (curr.right == null) {
                    curr.right = TreeNode(Some(key), Some(value), parent, null, null);
                } else {
                    _insert(curr, curr.right);
                }
            }
        }
        isEmpty match {
            case true => tree.right = TreeNode(Some(key), Some(value),null, null, null);
            case false => _insert(tree, tree.right);
        }
    }
    
    // key を探索する
    private def findSub(key: A): Option[TreeNode] = {
        @tailrec
        def _findSub(curr: TreeNode): Option[TreeNode] = curr match {
            case null => None;
            case node if compare(key, node.key.get) < 0 => _findSub(node.left);
            case node if compare(key, node.key.get) > 0 => _findSub(node.right);
            case node => Some(node);
        }
        _findSub(tree.right);
    }
    
    def find(key: A): Option[B] = {
        findSub(key) match {
            case None => None;
            case Some(node) => node.value;
        }
    }
    
    def delete(key: A): Unit = {
        def _delete(parent: TreeNode, curr: TreeNode): Unit = {
            if (curr.left == null && curr.right == null) {
                if (compare(curr.key.get, parent.left.key.get) < 0) parent.left = null else parent.right = null;
            } else if (curr.left == null) {
                if (compare(curr.key.get, parent.left.key.get) < 0) parent.left = curr.right else parent.right = curr.right;
                curr.right.parent == parent;
            } else if (curr.right == null) {
                if (compare(curr.key.get, parent.left.key.get) < 0) parent.left = curr.left else parent.right = curr.left;
                curr.left.parent = parent;
            } else {
                curr.key = curr.right.key;
                curr.value = curr.right.value;
                _delete(curr, curr.right);
            }
        }
        findSub(key) match {
            case None => ();
            case Some(node) => _delete(node.parent, node);
        }
    }

    // 先行巡回で要素を返す
    def fetchPreoder(): List[(A, B)] = {
        def _fetchPreoder(curr: TreeNode, ret: List[(A, B)]): List[(A, B)] = {
            if (curr == null) {
                ret;
            } else {
                val ret1 = (curr.key.get, curr.value.get) :: ret;
                val ret2 = _fetchPreoder(curr.left, ret1);
                val ret3 = _fetchPreoder(curr.right, ret2);
                ret3;
            }
        }
        _fetchPreoder(tree.right, Nil).reverse;
    }
    
    // 中間巡回で要素を返す
    def fetchInorder(): List[(A, B)] = {
        def _fetchInorder(curr: TreeNode, ret: List[(A, B)]): List[(A, B)] = {
            if (curr == null) {
                ret;
            } else {
                val ret1 = _fetchInorder(curr.left, ret);
                val ret2 = (curr.key.get, curr.value.get) :: ret1;
                val ret3 = _fetchInorder(curr.right, ret2);
                ret3;
            }
        }
        _fetchInorder(tree.right, Nil).reverse;
    }
}