Problem:
Binary Search Tree III Write a program which performs the following operations to a binary search tree $T$ by adding delete operation to B: Binary Search Tree II.  insert $k$: Insert a node containing $k$ as key into $T$.  find $k$: Report whether $T$ has a node containing $k$.  delete $k$: Delete a node containing $k$.  print : Print the keys of the binary search tree by inorder tree walk and  preorder tree walk respectively.  The operation delete $k$ for deleting a given node $z$ containing key $k$ from $T$ can be implemented by an algorithm which considers the following cases:  If $z$ has no children, we modify its parent $z.p$ to replace $z$ with NIL as its child (delete $z$).  If $z$ has only a single child, we "splice out" $z$ by making a new link between its child and its parent.  If $z$ has two children, we splice out $z$'s successor $y$ and replace $z$'s key with $y$'s key.  Input In the first line, the number of operations $m$ is given. In the following $m$ lines, operations represented by insert $k$, find $k$, delete $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  18
insert 8
insert 2
insert 3
insert 7
insert 22
insert 1
find 1
find 2
find 3
find 4
find 5
find 6
find 7
find 8
print
delete 3
delete 7
print  Sample Output 1  yes
yes
yes
no
no
no
yes
yes
 1 2 3 7 8 22
 8 2 1 3 7 22
 1 2 8 22
 8 2 1 22  Reference  Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

Solution (Python):
class Node:
    def __init__(self, key, parent=None, left=None, right=None):
        self.key = key
        self.parent = parent
        self.left = left
        self.right = right
         
 
def get_minimum(node):
    x = node
    while x.left is not None:
        x = x.left
    return x
 
class Tree:
    def __init__(self):
        self.root_node = None
         
    def insert(self, z):
        y = None 
        x = self.root_node 
        
        while x is not None:
            y = x 
            if z.key < x.key:
                x = x.left 
            else:
                x = x.right 
        
        z.parent = y
         
        if y is None:
            
            self.root_node = z
        elif z.key < y.key:
            y.left = z
        else:
            y.right = z
     
    def find(self, k):
        x = self.root_node
        while (x is not None) and (x.key != k):
            x = x.left if (k < x.key) else x.right            
        return x
 
    def delete_node(self, z):
        
        y = z if ((z.left is None) or (z.right is None)) else get_minimum(z.right)
        
        x = y.left if (y.left is not None) else y.right
        
        if x is not None:
            x.parent = y.parent
         
        if y.parent is None:
            self.root_node = x
        elif y is y.parent.left:
            y.parent.left = x
        else:
            y.parent.right = x
         
        if y is not z:
            z.key = y.key
    
 
    def print_preorder(self, node):
        print(f" {node.key}", end="")
        if node.left is not None:
            self.print_preorder(node.left)
        if node.right is not None:
            self.print_preorder(node.right)
 
    def print_inorder(self, node):
        if node.left is not None:
            self.print_inorder(node.left)
        print(f" {node.key}", end="")
        if node.right is not None:
            self.print_inorder(node.right)
 
    def print_nodes(self):
        if self.root_node is None:
            pass
        else:
            self.print_inorder(self.root_node)
            print("")
            self.print_preorder(self.root_node)
            print("")
         

tree = Tree()

m = int(input())
for _ in range(m):
    command = input().split()
    if command[0] == 'print':
        tree.print_nodes()
    elif command[0] == 'find':
        node = tree.find(int(command[1]))
        print("no") if (node is None) else print("yes")
    elif command[0] == 'delete':
        x = tree.find(int(command[1]))
        tree.delete_node(x)
    else:
        key = int(command[1])
        new_node = Node(key)
        tree.insert(new_node)

Solution (Python):



from sys import stdin
from random import randrange


class Tree():
    def __init__(self):
        self.root = None

    def insert(self, z):

        y = None
        x = self.root

        while x is not None:
            y = x
            if z.key < x.key:
                x = x.left
            else:
                x = x.right

        z.parent = y
        if y is None:
            self.root = z
        elif z.key < y.key:
            y.left = z
        else:
            y.right = z

    def find(self, key):
        x = self.root
        while x is not None:
            if key == x.key:
                return x
            elif key < x.key:
                x = x.left
            else:
                x = x.right
        return None

    def delete_node(self, x):
        if x.left is None and x.right is None:
            if x.parent is None:
                self.root = None
            elif x.parent.left == x:
                x.parent.left = None
            else:
                x.parent.right = None
        elif x.left is None:
            if x.parent is None:
                self.root = x.right
            elif x.parent.left == x:
                x.parent.left = x.right
            else:
                x.parent.right = x.right
            x.right.parent = x.parent
        elif x.right is None:
            if x.parent is None:
                self.root = x.left
            elif x.parent.left == x:
                x.parent.left = x.left
            else:
                x.parent.right = x.left
            x.left.parent = x.parent

    def delete(self, key):
        x = self.find(key)
        if x.left is None or x.right is None:
            self.delete_node(x)
        elif x.right.left is None:
            x.key = x.right.key
            self.delete_node(x.right)
        else:
            y = x.right.leftmost_child()
            x.key = y.key
            self.delete_node(y)

    def fold_inorder(self, f, init):
        def rec(node, b):
            nonlocal f, init

            if not node:
                return b
            else:
                return rec(node.right,
                           f(node.key,
                             rec(node.left, b)))

        return rec(self.root, init)

    def flatten_inorder(self):
        return self.fold_inorder(
            lambda a, b: b + [a],
            [])

    def foreach_inorder(self, f):

        def rec(node):
            if not node:
                return
            else:
                rec(node.left)
                f(node.key)
                rec(node.right)

        rec(self.root)

    def print_inorder(self):
        self.foreach_inorder(
            lambda a: print("", a, end="")
        )
        print()

    def print_preorder(self):

        def rec(node):
            if not node:
                return
            else:
                print("", node.key, end="")
                rec(node.left)
                rec(node.right)

        rec(self.root)
        print()

    def __str__(self):
        return str(self.root) if self.root else "()"


class Node():
    def __init__(self, key, parent=None, left=None, right=None):
        self.key = key
        self.parent = parent
        self.left = left
        self.right = right

    def rightmost_child(self):
        x = self
        while x.right is not None:
            x = x.right
        return x

    def leftmost_child(self):
        x = self
        while x.left is not None:
            x = x.left
        return x

    def __str__(self):
        return "({} {} {})".format(
            self.key, self.left, self.right)


def process(commands):
    T = Tree()
    for cmd in commands:
        if cmd[0] == "insert":
            T.insert(Node(int(cmd[1])))
        elif cmd[0] == "find":
            print("yes" if T.find(int(cmd[1])) else "no")
        elif cmd[0] == "delete":
            T.delete(int(cmd[1]))
        elif cmd[0] == "print":
            T.print_inorder()
            T.print_preorder()
    return T


def main():
    _ = int(stdin.readline())
    commands = []
    for line in stdin:
        commands.append(line.split())
    process(commands)


def test_a_case(name, commands, expected):
    result = str(process(commands))
    assert result == expected, name + " " + result


def test():
    test_a_case(
        "test1",
        [
        ],
        "()")
    test_a_case(
        "test2",
        [
            ["insert", "1"],
        ],
        "(1 None None)")
    test_a_case(
        "test3",
        [
            ["insert", "1"],
            ["delete", "1"],
        ],
        "()")


def random_test_repr(n, p, q, T):
    return "n:{}\np:{}\nq:{}\nT:{}".format(
        n, p, q, str(T))


def test_a_random_case(p, q):
    T = Tree()
    inserted = []

    for n in p:
        assert not T.find(n), \
            "Before Insert:\n" + \
            random_test_repr(n, p, q, str(T))
        T.insert(Node(n))
        assert T.find(n), \
            "After Insert:\n" + \
            random_test_repr(n, p, q, str(T))

        inserted.append(n)
        assert T.flatten_inorder() == sorted(inserted), \
            "Inorder(Inserting):\n" + \
            random_test_repr(n, p, q, str(T))

    for n in q:
        T.delete(n)
        assert not T.find(n), \
            "After Delete:\n" + \
            random_test_repr(n, p, q, str(T))

        inserted.remove(n)
        assert T.flatten_inorder() == sorted(inserted), \
            "Inorder(Deleting):\n" + \
            random_test_repr(n, p, q, str(T))


def random_array(l):
    arr = list(range(l))
    for i in range(l):
        j = randrange(l)
        tmp = arr[i]
        arr[i] = arr[j]
        arr[j] = tmp
    return arr


def random_test():
    N = 10000
    L = 7

    for i in range(N):
        test_a_random_case(
            random_array(L), random_array(L))


"""
test()
random_test()
exit()
"""

main()

Solution (Python):
import sys
class Node:
    __slots__ = ['key', 'left', 'right']
    def __init__(self, key):
        self.key = key
        self.left = self.right = None

root = None
def delete(target):
    def remove_node(p, c, a):
        if p.left == c:
            p.left = a
        else:
            p.right = a
    p, c = None, root
    while c.key != target:
        p, c = c, c.left if target < c.key else c.right
    if c.left is None:
        remove_node(p, c, c.right)
    elif c.right is None:
        remove_node(p, c, c.left)
    elif c.right.left is None:
        c.right.left = c.left
        remove_node(p, c, c.right)
    else:
        g = c.right
        while g.left.left:
            g = g.left
        c.key = g.left.key
        g.left = g.left.right

def find(target):
    result = root
    while result and target != result.key:
        result = result.left if target < result.key else result.right
    if result is None:
        return False
    else:
        return True

def insert(key):
    global root
    y = None  
    x = root
    while x:
        y = x
        x = x.left if key < x.key else x.right
    if y is None:  
        root = Node(key)
    elif key < y.key:
        y.left = Node(key)
    else:
        y.right = Node(key)

def in_order(node):
    if node is None:
        return ''
    return in_order(node.left) + f' {node.key}' + in_order(node.right)
def pre_order(node):
    if node is None:
        return ''
    return f' {node.key}' + pre_order(node.left) + pre_order(node.right)
input()
for e in sys.stdin:
    if e[0] == 'i':
        insert(int(e[7:]))
    elif e[0] == 'd':
        delete(int(e[7:]))
    elif e[0] == 'f':
        print('yes' if find(int(e[5:])) else 'no')
    else:
        print(in_order(root))
        print(pre_order(root))

Solution (Python):
class Node():
    def __init__(self, key):
        self.key = key
        self.parent = None
        self.left = None
        self.right = None

class Tree():
    def __init__(self):
        self.root = None
        self.list = []

    def insert(self, node):
        y = None                 
        x = self.root
        while x is not None:
            y = x                
            if node.key < x.key:
                x = x.left
            else:
                x = x.right
        node.parent = y

        if y is None:
            self.root = node
        elif node.key < y.key:
            y.left = node
        else:
            y.right = node

    def find(self, key):
        node = self.root
        while node is not None and key != node.key:
            if key < node.key:
                node = node.left
            else:
                node = node.right
        return node

    def delete(self, node):
        target_node = None
        if node.left is None or node.right is None:
            target_node = node
        else:
            target_node = self.get_successor(node.right)

        target_child = None
        if target_node.left is not None:
            target_child = target_node.left
        else:
            target_child = target_node.right

        if target_child is not None:
            target_child.parent = target_node.parent

        if target_node.parent is None:
            self.root = target_child
        else:
            if target_node is target_node.parent.left:
                target_node.parent.left = target_child
            else:
                target_node.parent.right = target_child

        if target_node is not node:
            node.key = target_node.key

    def get_successor(self, node):
        if node.left is None:
            return node

        while node.left is not None:
            node = node.left
        return node

    def parse_inorder(self, node):
        if node is None:
            return 
        self.parse_inorder(node.left)
        self.list.append(node.key)
        self.parse_inorder(node.right)

    def parse_preorder(self, node):
        if node is None:
            return
        self.list.append(node.key)
        self.parse_preorder(node.left)
        self.parse_preorder(node.right)

N = int(input())
T = Tree()
for _ in range(N):
    order, *key = input().split()
    if order == "print":
        T.list = []
        T.parse_inorder(T.root)
        print(" " + " ".join(map(str, T.list)))
        T.list = []
        T.parse_preorder(T.root)
        print(" " + " ".join(map(str, T.list)))
    elif order == "find":
        
        node = T.find(int(key[0]))
        if node is not None:
            print("yes")
        else:
            print("no")
    elif order == "delete":
        node = T.find(int(key[0]))
        if node is None:
            continue
        T.delete(node)
    else:
        node = Node(int(key[0]))
        T.insert(node)

Solution (Python):
class Node:
    def __init__(self, key):
        self.key = key
        self.parent = None
        self.left = None
        self.right = None
        
    def insert(self, z):
        if z.key < self.key:
            if self.left:
                self.left.insert(z)
            else:
                self.left = z
                z.parent = self
        else:
            if self.right:
                self.right.insert(z)
            else:
                self.right = z
                z.parent = self

    def find(self, key):
        if self.key == key:
            return True
        elif not self.left and not self.right:
            return False
        else:
            if key < self.key:
                return self.left.find(key)
            else:
                return self.right.find(key)
            
    def delete(self, key):
        if self.key == key:
            if not self.left and not self.right:
                if self.key < self.parent.key:
                    self.parent.left = None
                else:
                    self.parent.right = None
            elif self.left and self.right:
                A = [int(i) for i in self.ino().split()]
                ind = A.index(self.key)
                y = A[ind+1]
                self.delete(y)
                self.key = y
            else:
                if self.left:
                    self.left.parent = self.parent
                    if self.key < self.parent.key:
                        self.parent.left = self.left
                    else:
                        self.parent.right = self.left
                else:
                    self.right.parent = self.parent
                    if self.key < self.parent.key:
                        self.parent.left = self.right
                    else:
                        self.parent.right = self.right
        else:
            if self.key < key:
                self.right.delete(key)
            else:
                self.left.delete(key)
        
    def preo(self):
        tmp = ""
        tmp += " " + str(self.key)
        if self.left:
            tmp += self.left.preo()
        if self.right:
            tmp += self.right.preo()
        return tmp
    
    def ino(self):
        tmp = ""
        if self.left:
            tmp += self.left.ino()
        tmp += " " + str(self.key)
        if self.right:
            tmp += self.right.ino()
        return tmp
m = int(input())
root = None
for i in range(m):
    com = input().split()
    if com[0] == "insert":
        node = Node(int(com[1]))
        try:
            root.insert(node)
        except AttributeError :
            root = node
    elif com[0] == "find":
        try:
            if root.find(int(com[1])):
                print("yes")
            else:
                print("no")
        except AttributeError:
            print("no")
    elif com[0] == "delete":
        try:
            root.delete(int(com[1]))
        except AttributeError:
            print("failed deletion")
    else:
        try:
            print(root.ino())
            print(root.preo())
        except AttributeError:
            print("None")

Solution (Python):
class Node:
    def __init__(self, key, parent=None, left=None, right=None):
        self.key = key
        self.parent = parent
        self.left = left
        self.right = right


root = None

def insert(k):
    global root
    y = None
    x = root
    z = Node(k)

    while x is not None:
        y = x
        if z.key < x.key:
            x = x.left
        else:
            x = x.right

    z.parent = y
    if y is None:
        root = z
    else:
        if z.key < y.key:
            y.left = z
        else:
            y.right = z


def find(u, k):
    while u is not None and k != u.key:
        if k < u.key:
            u = u.left
        else:
            u = u.right
    return u


def treeMinimum(x):
    while x.left is not None:
        x = x.left
    return x


def treeSuccessor(x):
    if x.right is not None:
        return treeMinimum(x.right)
    y = x.parent
    while y is not None and x == y.right:
        x = y
        y = y.parent
    return y


def treeDelete(z):
    if z is None:
        return

    global root
    if z.left is None or z.right is None:
        y = z
    else:
        y = treeSuccessor(z)

    if y.left is not None:
        x = y.left
    else:
        x = y.right

    if x is not None:
        x.parent = y.parent

    if y.parent is None:
        root = x
    else:
        if y == y.parent.left:
            y.parent.left = x
        else:
            y.parent.right = x

    if y != z:
        z.key = y.key


def inorder(u):
    if u is None:
        return
    inorder(u.left)
    print(' %d' % u.key, end='')
    inorder(u.right)


def preorder(u):
    if u is None:
        return
    print(' %d' % u.key, end='')
    preorder(u.left)
    preorder(u.right)


n = int(input())
for i in range(n):
    cmd = input().split()
    if cmd[0] == 'insert':
        insert(int(cmd[1]))
    elif cmd[0] == 'find':
        if find(root, int(cmd[1])) is not None:
            print('yes')
        else:
            print('no')
    elif cmd[0] == 'delete':
        treeDelete(find(root, int(cmd[1])))
    elif cmd[0] == 'print':
        inorder(root)
        print()
        preorder(root)
        print()

Solution (Python):
class Node:
	def __init__(self, key):
		self.key = key
		self.left = self.right = self.parent = None

class BST:
	def __init__(self):
		self.root = None
	
	def insert(self, key):
		parent = None
		current = self.root
		while current != None:
			parent = current
			if key < current.key:
				current = current.left
			else:
				current = current.right
		new = Node(key)
		new.parent = parent
		if parent == None:
			self.root = new
		elif key < parent.key:
			parent.left = new
		else:
			parent.right = new		
	
	def find(self, key):
		current = self.root
		while current != None:
			if key == current.key:
				return current
			if key < current.key:
				current = current.left
			else:
				current = current.right
		return None
		
	def delete(self, key):
		target = self.find(key)
		if target == None:
			return

		parent = target.parent
		if target.left == None or target.right == None:
			child = None
			if target.left != None:
				child = target.left
			elif target.right != None:
				child = target.right
			
			if child != None:
				child.parent = parent
	
			if parent == None:
				self.root = child
			elif parent.left == target:
				parent.left = child
			else:
				parent.right = child
		else:
			current = target.right
			while current.left != None:
				current = current.left
			target.key = current.key
			parent = current.parent
			if current.right != None:
				parent.left = current.right
				current.right.parent = parent
			else:
				if parent.left == current:
					parent.left = None
				else:
					parent.right = None
	
	def print(self):
		self.print_in_order(self.root)
		print()
		self.print_pre_order(self.root)
		print()
		
	def print_in_order(self, node):
		if node != None:
			self.print_in_order(node.left)
			print(' ' + str(node.key), end='')
			self.print_in_order(node.right)
		
	def print_pre_order(self, node):
		if node != None:
			print(' ' + str(node.key), end='')
			self.print_pre_order(node.left)
			self.print_pre_order(node.right)		

n = int(input())
bst = BST()
for i in range(n):
	cmd = list(map(str, input().split()))
	if cmd[0] == 'print':
		bst.print()
	else:
		key = int(cmd[1])
		if cmd[0] == 'insert':
			bst.insert(key)
		elif cmd[0] == 'find':
			if bst.find(key) != None:
				print('yes')
			else:
				print('no')
		else:
			bst.delete(key)

Solution (Python):

class Tree:
    def __init__(self):
        self.root = None
        self.size = 0
    
    def delete(self, key):
        nd = self.find(key)
        self._delete_node(nd)

    def _delete_node(self, nd):
        if not nd: raise 
        dl = nd.num_child()
        parent = nd.parent
        if dl == 0:
            if parent.left == nd: parent.left = None
            elif parent.right == nd: parent.right = None
        elif dl == 1:
            l,r = nd.left,nd.right
            if l:
                l.parent = parent
                self._reconnect(parent, nd, l)
            elif r:
                r.parent = parent
                self._reconnect(parent, nd, r)
        else: 
            nextnd = self._find_next_node(nd)
            nd.key = nextnd.key
            self._delete_node(nextnd)

    def _find_next_node(self, nd):
        """ Find a node that is next node to nd by "Inorder".
        """
        return self._find_next_left(nd.right)

    def _find_next_left(self, nd):
        """ Find most left node about a given node.
        """
        if nd.left: return self._find_next_left(nd.left)
        else: return nd

    def _reconnect(self, p, t, c):
        """ Change p's child into c from t.
            And change c's parent into p from t.
        """
        if p.left == t: p.left = c
        elif p.right == t: p.right = c

    def find(self, key):
        return self._find(key, self.root)

    def _find(self, key, nd):
        if not nd: return None
        if nd.key == key: return nd
        if key < nd.key:
            return self._find(key, nd.left)
        else:
            return self._find(key, nd.right)
    
    def printorder(self):
        self._preorder_walk(self.root)
        print()
        self._inorder_walk(self.root)
        print()

    def _inorder_walk(self, nd):
        print(' {0}'.format(nd.key), end='')
        if nd.left: self._inorder_walk(nd.left)
        if nd.right: self._inorder_walk(nd.right)

    def _preorder_walk(self, nd):
        if nd.left: self._preorder_walk(nd.left)
        print(' {0}'.format(nd.key), end='')
        if nd.right: self._preorder_walk(nd.right)

class Node:
    def num_child(self):
        d = 1 if self.left else 0
        d += 1 if self.right else 0
        return d
    def __init__(self, key):
        self.key = key
        self.right,self.left = None,None
        self.parent = None
    def __str__(self):
        return 'node key: ' + str(self.key)

def insert(T, z):
    y = None
    x = T.root
    while not x == None:
        y = x
        if z.key < x.key:
            x = x.left
        else:
            x = x.right
    z.parent = y
    if z.parent == None:
        T.root = z
    elif z.key < y.key:
        y.left = z
    else:
        y.right = z
    T.size += 1

m = int(input())
T = Tree()
for _ in range(m):
    ss = input().split()
    op = ss[0]
    if op == 'insert':
        v = int(ss[1])
        insert(T, Node(v))
    elif op == 'print':
        T.printorder()
    elif op == 'find':
        v = int(ss[1])
        if T.find(v): print('yes')
        else: print('no')
    elif op == 'delete':
        v = int(ss[1])
        T.delete(v)