#include <stdio.h>
    #include <stdlib.h>
    #define MAX 10
    #define MAXQ 10

    // Node structure for binary tree - contains data and pointers to left and right children
    typedef struct Node {
        int data;
        struct Node* lchild;
        struct Node* rchild;
    } Node;

    // Queue structure for level order traversal
    typedef struct {
        Node* arr[MAX];
        int front;
        int rear;
    } queue;

    // Check if queue is full
    int isFullq(queue* q) {
        return (q->rear == MAX-1);
    }

    // Check if queue is empty
    int isEmptyq(queue* q) {
        return (q->front == -1);
    }

    // Add element to queue
    void enqueue(queue* q, Node* value) {
        if(isFullq(q)) {
            printf("Overflow");
            return;
        }
        else {
            q->arr[++(q->rear)] = value;
            if(q->front == -1) {
                q->front = 0;
            }
        }
    }

    // Remove and return element from queue
    Node* dequeue(queue* q) {
        Node* x;
        if(isEmptyq(q)) {
            printf("Underflow");
            return NULL;
        }
        else if(q->front == q->rear) {
            x = q->arr[q->front];
            q->front = q->rear = -1;
            return x;
        }
        else {
            x = q->arr[(q->front)++];
            return x;
        }
    }

    // Stack structure for iterative traversals
    typedef struct {
        Node* arr[MAX];
        int top;
    } STACK;

    // Check if stack is full
    int isFull(STACK* s) {
        return s->top == MAX-1;
    }

    // Check if stack is empty
    int isEmpty(STACK* s) {
        return s->top == -1;
    }

    // Push element onto stack
    void push(STACK* s, Node* value) {
        if(isFull(s)) {
            printf("Stack Overflow");
            return;
        }
        else {
            s->arr[++(s->top)] = value;
        }
    }

    // Pop and return element from stack
    Node* pop(STACK* s) {
        if(isEmpty(s)) {
            printf("Stack underflow");
            return NULL;
        }
        else {
            return s->arr[(s->top)--];
        }
    }

    // Create new tree node
    Node* getNode() {
        Node* newNode = (Node*)malloc(sizeof(Node));
        newNode->data = 0;
        newNode->lchild = NULL;
        newNode->rchild = NULL;
        return newNode;
    }

    // Recursively create binary tree
    Node* createTree(int item) {
        if(item != -1) {
            Node* t = getNode();
            t->data = item;

            int x;
            printf("Enter the left child of %d (-1 for no child): ", item);
            scanf("%d", &x);
            t->lchild = createTree(x);

            printf("Enter the right child of %d (-1 for no child): ", item);
            scanf("%d", &x);
            t->rchild = createTree(x);

            return t;
        }
        return NULL;
    }

    // Recursive preorder traversal (Root-Left-Right)
    void preorder(Node* root) {
        if(root != NULL) {
            printf("%d ", root->data);
            preorder(root->lchild);
            preorder(root->rchild);
        }
    }

    // Recursive inorder traversal (Left-Root-Right)
    void inorder(Node* root) {
        if(root != NULL) {
            inorder(root->lchild);
            printf("%d ", root->data);
            inorder(root->rchild);
        }
    }

    // Recursive postorder traversal (Left-Right-Root)
    void postorder(Node* root) {
        if(root != NULL) {
            postorder(root->lchild);
            postorder(root->rchild);
            printf("%d ", root->data);
        }
    }

    // Level order traversal using queue
    void levelorder(Node* root) {
        if(root == NULL) return;
        queue q;
        q.front = -1;
        q.rear = -1;
        Node* t = root;
        printf("%d ", t->data);
        enqueue(&q, t);
        while(!isEmptyq(&q)) {
            t = dequeue(&q);
            if(t->lchild) {
                printf("%d ", t->lchild->data);
                enqueue(&q, t->lchild);
            }
            if(t->rchild) {
                printf("%d ", t->rchild->data);
                enqueue(&q, t->rchild);
            }
        }
    }

    // Iterative preorder traversal using stack
    void itrpre(Node* root) {
        STACK s;
        s.top = -1;
        Node* t = root;
        while(t != NULL || !isEmpty(&s)) {
            if(t != NULL) {
                printf("%d ", t->data);
                push(&s, t);
                t = t->lchild;
            }
            else {
                t = pop(&s);
                t = t->rchild;
            }
        }
    }

    // Iterative inorder traversal using stack
    void itrin(Node* root) {
        STACK s;
        s.top = -1;
        Node* t = root;
        while(t != NULL || !isEmpty(&s)) {
            if(t != NULL) {
                push(&s, t);
                t = t->lchild;
            }
            else {
                t = pop(&s);
                printf("%d ", t->data);
                t = t->rchild;
            }
        }
    }

    // Iterative postorder traversal using stack
    void itrpost(Node* root) {
        STACK s;
        s.top = -1;
        Node* t = root;
        Node* visit = NULL;
        while(t != NULL || !isEmpty(&s)) {
            if(t != NULL) {
                push(&s, t);
                t = t->lchild;
            }
            else {
                Node* p = s.arr[s.top];
                if(p->rchild != NULL && p->rchild != visit)
                    t = p->rchild;
                else {
                    printf("%d ", p->data);
                    visit = pop(&s);
                }
            }
        }
    }

    // Count total number of nodes in tree
    int count(Node* root) {
        Node* p = root;
        int x, y;
        if(p != NULL) {
            x = count(p->lchild);
            y = count(p->rchild);
            return x + y + 1;
        }
        return 0;
    }

    // Calculate sum of all node values in tree
    int sumnodes(Node* root) {
        Node* p = root;
        int x, y;
        if(p != NULL) {
            x = sumnodes(p->lchild);
            y = sumnodes(p->rchild);
            return x + y + p->data;
        }
        return 0;
    }

    // Search for element in tree
    int Search(Node* root, int ele) {
        if(root == NULL)
            return 0;
        if(root->data == ele)
            return 1;
        if(Search(root->lchild, ele))
            return 1;
        return Search(root->rchild, ele);
    }

    // Display menu of operations
    void displayMenu() {
        printf("\n=== Binary Tree Operations ===\n");
        printf("1. Create a new tree\n");
        printf("2. Recursive Preorder Traversal\n");
        printf("3. Recursive Inorder Traversal\n");
        printf("4. Recursive Postorder Traversal\n");
        printf("5. Iterative Preorder Traversal\n");
        printf("6. Iterative Inorder Traversal\n");
        printf("7. Iterative Postorder Traversal\n");
        printf("8. Level Order Traversal\n");
        printf("9. Count Nodes\n");
        printf("10. Sum of Nodes\n");
        printf("11. Search Element\n");
        printf("0. Exit\n");
        printf("Enter your choice: ");
    }

    int main() {
        Node* root = NULL;
        int choice, rootnum, searchEle;

        do {
            displayMenu();
            scanf("%d", &choice);

            switch(choice) {
                case 1:
                    printf("Enter data for root node: ");
                    scanf("%d", &rootnum);
                    root = createTree(rootnum);
                    printf("Tree created successfully!\n");
                    break;
                case 2:
                    printf("Recursive Preorder Traversal: ");
                    preorder(root);
                    printf("\n");
                    break;
                case 3:
                    printf("Recursive Inorder Traversal: ");
                    inorder(root);
                    printf("\n");
                    break;
                case 4:
                    printf("Recursive Postorder Traversal: ");
                    postorder(root);
                    printf("\n");
                    break;
                case 5:
                    printf("Iterative Preorder Traversal: ");
                    itrpre(root);
                    printf("\n");
                    break;
                case 6:
                    printf("Iterative Inorder Traversal: ");
                    itrin(root);
                    printf("\n");
                    break;
                case 7:
                    printf("Iterative Postorder Traversal: ");
                    itrpost(root);
                    printf("\n");
                    break;
                case 8:
                    printf("Level Order Traversal: ");
                    levelorder(root);
                    printf("\n");
                    break;
                case 9:
                    printf("Number of nodes: %d\n", count(root));
                    break;
                case 10:
                    printf("Sum of all nodes: %d\n", sumnodes(root));
                    break;
                case 11:
                    printf("Enter element to search: ");
                    scanf("%d", &searchEle);
                    if(Search(root, searchEle))
                        printf("Element found in the tree\n");
                    else
                        printf("Element not found in the tree\n");
                    break;
                case 0:
                    printf("Exiting program...\n");
                    break;
                default:
                    printf("Invalid choice! Please try again.\n");
            }
        } while(choice != 0);

        return 0;
    }