Iterator

The Iterator design pattern is a behavioral design pattern that provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. This pattern is particularly useful for collections like lists, trees, and other complex data structures.

from typing import Any, Optional
from abc import ABC, abstractmethod

# Node class for the binary tree
class Node:
    def __init__(self, value: Any):
        self.value = value
        self.left: Optional[Node] = None
        self.right: Optional[Node] = None

# Iterator Interface
class Iterator(ABC):
    @abstractmethod
    def __next__(self) -> Any:
        pass

    @abstractmethod
    def __iter__(self) -> 'Iterator':
        pass

# Concrete Iterator for in-order traversal
class InOrderIterator(Iterator):
    def __init__(self, root: Optional[Node]):
        self.stack = []
        self._push_left(root)

    def _push_left(self, node: Optional[Node]):
        while node:
            self.stack.append(node)
            node = node.left

    def __next__(self) -> Any:
        if not self.stack:
            raise StopIteration

        node = self.stack.pop()
        value = node.value
        if node.right:
            self._push_left(node.right)

        return value

    def __iter__(self) -> 'InOrderIterator':
        return self

# Aggregate Interface
class Aggregate(ABC):
    @abstractmethod
    def create_iterator(self) -> Iterator:
        pass

# Concrete Aggregate for the binary tree
class BinaryTree(Aggregate):
    def __init__(self, root: Optional[Node]):
        self.root = root

    def create_iterator(self) -> Iterator:
        return InOrderIterator(self.root)

# Client code
if __name__ == "__main__":
    # Create a binary tree
    root = Node(4)
    root.left = Node(2)
    root.right = Node(6)
    root.left.left = Node(1)
    root.left.right = Node(3)
    root.right.left = Node(5)
    root.right.right = Node(7)

    tree = BinaryTree(root)
    iterator = tree.create_iterator()

    for value in iterator:
        print(value)