



from __future__ import annotations

from abc import abstractmethod
from collections.abc import Iterable
from typing import Generic, Protocol, TypeVar

class      snake_case__       (A__	):







						"""simple docstring"""




						@abstractmethod
						def __lt__(     self      ,     __lowercase						)      ->   bool:
									"""simple docstring"""




									pass

						@abstractmethod
						def __gt__(     self      ,     __lowercase						)      ->   bool:
									"""simple docstring"""




									pass

						@abstractmethod
						def __eq__(     self      ,     __lowercase						)      ->   bool:
									"""simple docstring"""




									pass




_lowercase	:   List[str]    	=TypeVar("T", bound=Comparable)

class      snake_case__       (Generic[T]	):







						"""simple docstring"""




						def __init__(     self						)      ->   None:
									"""simple docstring"""




									a__     :		list[T]		 =						[]
									a__     :		int		 =						0

						def __repr__(     self						)      ->   str:
									"""simple docstring"""




									return str(self.h						)

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   int | None:
									"""simple docstring"""




									if child_idx > 0:
												return (child_idx - 1) // 2
									return None

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   int | None:
									"""simple docstring"""




									a__     :		int		 =						2 * parent_idx + 1
									if left_child_index < self.heap_size:
												return left_child_index
									return None

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   int | None:
									"""simple docstring"""




									a__     :		Optional[Any]		 =						2 * parent_idx + 2
									if right_child_index < self.heap_size:
												return right_child_index
									return None

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   None:
									"""simple docstring"""




									if index < self.heap_size:
												a__     :		int		 =						index
												a__     :		Union[str, Any]		 =						self.left_child_idx(__lowercase						)
												a__     :		Any		 =						self.right_child_idx(__lowercase						)
												# check which child is larger than its parent
												if left_child is not None and self.h[left_child] > self.h[violation]:
															a__     :		Union[str, Any]		 =						left_child
												if right_child is not None and self.h[right_child] > self.h[violation]:
															a__     :		List[Any]		 =						right_child
												# if violation indeed exists
												if violation != index:
															# swap to fix the violation
															a__ ,		a__     :		Tuple		 =						self.h[index], self.h[violation]
															# fix the subsequent violation recursively if any
															self.max_heapify(__lowercase						)

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   None:
									"""simple docstring"""




									a__     :		Tuple		 =						list(__lowercase						)
									a__     :		Union[str, Any]		 =						len(self.h						)
									if self.heap_size > 1:
												# max_heapify from right to left but exclude leaves (last level)
												for i in range(self.heap_size // 2 - 1      ,     -1      ,     -1						):
															self.max_heapify(__lowercase						)

						def 							SCREAMING_SNAKE_CASE__(     self						)      ->   T:
									"""simple docstring"""




									if self.heap_size >= 2:
												a__     :		Tuple		 =						self.h[0]
												a__     :		Union[str, Any]		 =						self.h.pop(-1						)
												self.heap_size -= 1
												self.max_heapify(0						)
												return me
									elif self.heap_size == 1:
												self.heap_size -= 1
												return self.h.pop(-1						)
									else:
												raise Exception("""Empty heap"""						)

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   None:
									"""simple docstring"""




									self.h.append(__lowercase						)
									a__     :		Optional[int]		 =						(self.heap_size - 1) // 2
									self.heap_size += 1
									while idx >= 0:
												self.max_heapify(__lowercase						)
												a__     :		Union[str, Any]		 =						(idx - 1) // 2

						def 							SCREAMING_SNAKE_CASE__(     self						)      ->   None:
									"""simple docstring"""




									a__     :		Any		 =						self.heap_size
									for j in range(size - 1      ,     0      ,     -1						):
												a__ ,		a__     :		Dict		 =						self.h[j], self.h[0]
												self.heap_size -= 1
												self.max_heapify(0						)
									a__     :		List[Any]		 =						size


if __name__ == "__main__":
		import doctest

		# run doc test
		doctest.testmod()

		# demo
		for unsorted in [
		    [0],
		    [2],
		    [3, 5],
		    [5, 3],
		    [5, 5],
		    [0, 0, 0, 0],
		    [1, 1, 1, 1],
		    [2, 2, 3, 5],
		    [0, 2, 2, 3, 5],
		    [2, 5, 3, 0, 2, 3, 0, 3],
		    [6, 1, 2, 7, 9, 3, 4, 5, 10, 8],
		    [103, 9, 1, 7, 11, 15, 25, 201, 209, 107, 5],
		    [-45, -2, -5],
		]:
				print(f'unsorted array: {unsorted}')

				_lowercase	:   Heap[int]    	=Heap()
				heap.build_max_heap(unsorted)
				print(f'after build heap: {heap}')

				print(f'max value: {heap.extract_max()}')
				print(f'after max value removed: {heap}')

				heap.insert(100)
				print(f'after new value 100 inserted: {heap}')

				heap.heap_sort()
				print(f'heap-sorted array: {heap}\n')









from __future__ import annotations

from abc import abstractmethod
from collections.abc import Iterable
from typing import Generic, Protocol, TypeVar

class      snake_case__       (A__	):







						"""simple docstring"""




						@abstractmethod
						def __lt__(     self      ,     __lowercase						)      ->   bool:
									"""simple docstring"""




									pass

						@abstractmethod
						def __gt__(     self      ,     __lowercase						)      ->   bool:
									"""simple docstring"""




									pass

						@abstractmethod
						def __eq__(     self      ,     __lowercase						)      ->   bool:
									"""simple docstring"""




									pass




_lowercase	:   List[str]    	=TypeVar("T", bound=Comparable)

class      snake_case__       (Generic[T]	):







						"""simple docstring"""




						def __init__(     self						)      ->   None:
									"""simple docstring"""




									a__     :		list[T]		 =						[]
									a__     :		int		 =						0

						def __repr__(     self						)      ->   str:
									"""simple docstring"""




									return str(self.h						)

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   int | None:
									"""simple docstring"""




									if child_idx > 0:
												return (child_idx - 1) // 2
									return None

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   int | None:
									"""simple docstring"""




									a__     :		int		 =						2 * parent_idx + 1
									if left_child_index < self.heap_size:
												return left_child_index
									return None

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   int | None:
									"""simple docstring"""




									a__     :		Optional[Any]		 =						2 * parent_idx + 2
									if right_child_index < self.heap_size:
												return right_child_index
									return None

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   None:
									"""simple docstring"""




									if index < self.heap_size:
												a__     :		int		 =						index
												a__     :		Union[str, Any]		 =						self.left_child_idx(__lowercase						)
												a__     :		Any		 =						self.right_child_idx(__lowercase						)
												# check which child is larger than its parent
												if left_child is not None and self.h[left_child] > self.h[violation]:
															a__     :		Union[str, Any]		 =						left_child
												if right_child is not None and self.h[right_child] > self.h[violation]:
															a__     :		List[Any]		 =						right_child
												# if violation indeed exists
												if violation != index:
															# swap to fix the violation
															a__ ,		a__     :		Tuple		 =						self.h[index], self.h[violation]
															# fix the subsequent violation recursively if any
															self.max_heapify(__lowercase						)

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   None:
									"""simple docstring"""




									a__     :		Tuple		 =						list(__lowercase						)
									a__     :		Union[str, Any]		 =						len(self.h						)
									if self.heap_size > 1:
												# max_heapify from right to left but exclude leaves (last level)
												for i in range(self.heap_size // 2 - 1      ,     -1      ,     -1						):
															self.max_heapify(__lowercase						)

						def 							SCREAMING_SNAKE_CASE__(     self						)      ->   T:
									"""simple docstring"""




									if self.heap_size >= 2:
												a__     :		Tuple		 =						self.h[0]
												a__     :		Union[str, Any]		 =						self.h.pop(-1						)
												self.heap_size -= 1
												self.max_heapify(0						)
												return me
									elif self.heap_size == 1:
												self.heap_size -= 1
												return self.h.pop(-1						)
									else:
												raise Exception("""Empty heap"""						)

						def 							SCREAMING_SNAKE_CASE__(     self      ,     __lowercase						)      ->   None:
									"""simple docstring"""




									self.h.append(__lowercase						)
									a__     :		Optional[int]		 =						(self.heap_size - 1) // 2
									self.heap_size += 1
									while idx >= 0:
												self.max_heapify(__lowercase						)
												a__     :		Union[str, Any]		 =						(idx - 1) // 2

						def 							SCREAMING_SNAKE_CASE__(     self						)      ->   None:
									"""simple docstring"""




									a__     :		Any		 =						self.heap_size
									for j in range(size - 1      ,     0      ,     -1						):
												a__ ,		a__     :		Dict		 =						self.h[j], self.h[0]
												self.heap_size -= 1
												self.max_heapify(0						)
									a__     :		List[Any]		 =						size


if __name__ == "__main__":
		import doctest

		# run doc test
		doctest.testmod()

		# demo
		for unsorted in [
		    [0],
		    [2],
		    [3, 5],
		    [5, 3],
		    [5, 5],
		    [0, 0, 0, 0],
		    [1, 1, 1, 1],
		    [2, 2, 3, 5],
		    [0, 2, 2, 3, 5],
		    [2, 5, 3, 0, 2, 3, 0, 3],
		    [6, 1, 2, 7, 9, 3, 4, 5, 10, 8],
		    [103, 9, 1, 7, 11, 15, 25, 201, 209, 107, 5],
		    [-45, -2, -5],
		]:
				print(f'unsorted array: {unsorted}')

				_lowercase	:   Heap[int]    	=Heap()
				heap.build_max_heap(unsorted)
				print(f'after build heap: {heap}')

				print(f'max value: {heap.extract_max()}')
				print(f'after max value removed: {heap}')

				heap.insert(100)
				print(f'after new value 100 inserted: {heap}')

				heap.heap_sort()
				print(f'heap-sorted array: {heap}\n')




