
from collections.abc import Iterable
from typing import Any
class 	A__   :





							def __init__( self  :   Union[str, Any]     , _UpperCAmelCase  :   Tuple = None				)						->		Optional[Any]:



											"""simple docstring"""


											__lowercase								=					value
											__lowercase								=					None  # Added in order to delete a node easier
											__lowercase								=					None
											__lowercase								=					None





							def __repr__( self  :   str				)						->		str:



											"""simple docstring"""


											from pprint import pformat

											if self.left is None and self.right is None:
															return str(self.value				)
											return pformat({f"""{self.value}""": (self.left, self.right)}     , indent=1				)






class 	A__   :





							def __init__( self  :   int     , _UpperCAmelCase  :   Optional[Any] = None				)						->		str:



											"""simple docstring"""


											__lowercase								=					root





							def __str__( self  :   List[Any]				)						->		str:



											"""simple docstring"""


											return str(self.root				)





							def 			a__ ( self  :   int     , _UpperCAmelCase  :   str     , _UpperCAmelCase  :   Optional[Any]				)						->		None:



											"""simple docstring"""


											if new_children is not None:  # reset its kids
															__lowercase								=					node.parent
											if node.parent is not None:  # reset its parent
															if self.is_right(lowercase_				):  # If it is the right children
																			__lowercase								=					new_children
															else:
																			__lowercase								=					new_children
											else:
															__lowercase								=					new_children





							def 			a__ ( self  :   Tuple     , _UpperCAmelCase  :   Any				)						->		bool:



											"""simple docstring"""


											if node.parent and node.parent.right:
															return node == node.parent.right
											return False





							def 			a__ ( self  :   List[str]				)						->		bool:



											"""simple docstring"""


											return self.root is None





							def 			a__ ( self  :   Tuple     , _UpperCAmelCase  :   Optional[int]				)						->		None:



											"""simple docstring"""


											__lowercase								=					Node(lowercase_				)  # create a new Node
											if self.empty():  # if Tree is empty
															__lowercase								=					new_node  # set its root
											else:  # Tree is not empty
															__lowercase								=					self.root  # from root
															if parent_node is None:
																			return
															while True:  # While we don't get to a leaf
																			if value < parent_node.value:  # We go left
																							if parent_node.left is None:
																											__lowercase								=					new_node  # We insert the new node in a leaf
																											break
																							else:
																											__lowercase								=					parent_node.left
																			else:
																							if parent_node.right is None:
																											__lowercase								=					new_node
																											break
																							else:
																											__lowercase								=					parent_node.right
															__lowercase								=					parent_node





							def 			a__ ( self  :   List[str]     , *_UpperCAmelCase  :   Union[str, Any]				)						->		None:



											"""simple docstring"""


											for value in values:
															self.__insert(lowercase_				)





							def 			a__ ( self  :   List[Any]     , _UpperCAmelCase  :   Optional[int]				)						->		Node | None:



											"""simple docstring"""


											if self.empty():
															raise IndexError('Warning: Tree is empty! please use another.'				)
											else:
															__lowercase								=					self.root
															# use lazy evaluation here to avoid NoneType Attribute error
															while node is not None and node.value is not value:
																			__lowercase								=					node.left if value < node.value else node.right
															return node





							def 			a__ ( self  :   Dict     , _UpperCAmelCase  :   List[Any] = None				)						->		Node | None:



											"""simple docstring"""


											if node is None:
															if self.root is None:
																			return None
															__lowercase								=					self.root

											if not self.empty():
															while node.right is not None:
																			__lowercase								=					node.right
											return node





							def 			a__ ( self  :   int     , _UpperCAmelCase  :   List[Any] = None				)						->		Node | None:



											"""simple docstring"""


											if node is None:
															__lowercase								=					self.root
											if self.root is None:
															return None
											if not self.empty():
															__lowercase								=					self.root
															while node.left is not None:
																			__lowercase								=					node.left
											return node





							def 			a__ ( self  :   Optional[int]     , _UpperCAmelCase  :   Tuple				)						->		None:



											"""simple docstring"""


											__lowercase								=					self.search(lowercase_				)  # Look for the node with that label
											if node is not None:
															if node.left is None and node.right is None:  # If it has no children
																			self.__reassign_nodes(lowercase_     , lowercase_				)
															elif node.left is None:  # Has only right children
																			self.__reassign_nodes(lowercase_     , node.right				)
															elif node.right is None:  # Has only left children
																			self.__reassign_nodes(lowercase_     , node.left				)
															else:
																			__lowercase								=					self.get_max(
																			    node.left				)  # Gets the max value of the left branch
																			self.remove(tmp_node.value				)  # type: ignore
																			__lowercase								=					(
																			    tmp_node.value  # type: ignore
																			)  # Assigns the value to the node to delete and keep tree structure





							def 			a__ ( self  :   List[Any]     , _UpperCAmelCase  :   str				)						->		Iterable:



											"""simple docstring"""


											if node is not None:
															yield node  # Preorder Traversal
															yield from self.preorder_traverse(node.left				)
															yield from self.preorder_traverse(node.right				)





							def 			a__ ( self  :   List[Any]     , _UpperCAmelCase  :   Optional[Any]=None				)						->		Any:



											"""simple docstring"""


											if traversal_function is None:
															return self.preorder_traverse(self.root				)
											else:
															return traversal_function(self.root				)





							def 			a__ ( self  :   List[str]     , _UpperCAmelCase  :   Tuple     , _UpperCAmelCase  :   str				)						->		None:



											"""simple docstring"""


											if node:
															self.inorder(lowercase_     , node.left				)
															arr.append(node.value				)
															self.inorder(lowercase_     , node.right				)





							def 			a__ ( self  :   List[Any]     , _UpperCAmelCase  :   Dict     , _UpperCAmelCase  :   int				)						->		int:



											"""simple docstring"""


											__lowercase								=					[]
											self.inorder(lowercase_     , lowercase_				)  # append all values to list using inorder traversal
											return arr[k - 1]






def 							__SCREAMING_SNAKE_CASE   (		SCREAMING_SNAKE_CASE       :      Node | None			)     ->						Dict:
				__lowercase								=					[]
				if curr_node is not None:
								__lowercase								=					postorder(curr_node.left			) + postorder(curr_node.right			) + [curr_node]
				return node_list




def 							__SCREAMING_SNAKE_CASE   (		)     ->						List[Any]:
				__lowercase								=					(8, 3, 6, 1, 10, 14, 13, 4, 7)
				__lowercase								=					BinarySearchTree()
				for i in testlist:
								t.insert(_A			)

				# Prints all the elements of the list in order traversal
				print(_A			)

				if t.search(6			) is not None:
								print('The value 6 exists'			)
				else:
								print('The value 6 doesn\'t exist'			)

				if t.search(-1			) is not None:
								print('The value -1 exists'			)
				else:
								print('The value -1 doesn\'t exist'			)

				if not t.empty():
								print('Max Value: '    ,							t.get_max().value			)  # type: ignore
								print('Min Value: '    ,							t.get_min().value			)  # type: ignore

				for i in testlist:
								t.remove(_A			)
								print(_A			)


if __name__ == "__main__":
							import doctest

							doctest.testmod(verbose=True)








from __future__ import annotations




def 			UpperCAmelCase__				(			_A      : float	,      _A      : float	,      _A      : float	,      ):





  '''simple docstring'''







  if (electron_conc, hole_conc, intrinsic_conc).count(0							) != 1:
    raise ValueError('''You cannot supply more or less than 2 values'''							)
  elif electron_conc < 0:
    raise ValueError('''Electron concentration cannot be negative in a semiconductor'''							)
  elif hole_conc < 0:
    raise ValueError('''Hole concentration cannot be negative in a semiconductor'''							)
  elif intrinsic_conc < 0:
    raise ValueError(
        '''Intrinsic concentration cannot be negative in a semiconductor'''							)
  elif electron_conc == 0:
    return (
        "electron_conc",
        intrinsic_conc**2 / hole_conc,
    )
  elif hole_conc == 0:
    return (
        "hole_conc",
        intrinsic_conc**2 / electron_conc,
    )
  elif intrinsic_conc == 0:
    return (
        "intrinsic_conc",
        (electron_conc * hole_conc) ** 0.5,
    )
  else:
    return (-1, -1)


if __name__ == "__main__":
       import doctest

       doctest.testmod()
