#ifndef BINARYTREE_H
#define BINARYTREE_H

#pragma once
#include <iostream>
#include <cassert>
#include <vector>
#include <stack>
#include <queue>
template<typename T>
class Node {
public:
    T data;
    Node* left;
    Node* right;

    explicit Node(T val) : data(val), left(nullptr), right(nullptr) {
    }
};

template<typename T>
class Tree {
public:
    Node<T>* root;
    T refvalue; //标记符

    Tree() : root(nullptr) {
    }

    static void InitTree(Tree<T>* bt, T ref);

    static void CreateTree_1(Tree<T>* bt);

    static void CreateTree_1(Tree<T>* bt, Node<T>** t);

    static void CreateTree_2(Tree<T>* bt, Node<T>*&t);

    static void PreOrder(Tree<T>* bt);

    static void PreOrder(Node<T>* root);

    static void InOrder(Tree<T>* bt);

    static void InOrder(Node<T>* root);

    static void PostOrder(Tree<T>* bt);

    static void PostOrder(Node<T>* root);

    static void LevelOrder(Tree<T>* bt);

    static void LevelOrder(Node<T>* root);
    static int Size(Tree<T> *bt);
    static int Size(Node<T> *root);
};

template<typename T>
void Tree<T>::InitTree(Tree<T>* bt, T ref) {
    bt->root = nullptr;
    bt->refvalue = ref;
}

template<typename T>
void Tree<T>::CreateTree_1(Tree<T>* bt) {
    // CreateTree_1(bt, &(bt->root));
    CreateTree_2(bt, bt->root);
}


template<typename T>
void Tree<T>::CreateTree_1(Tree<T>* bt, Node<T>** t) {
    T item;
    std::cin >> item;
    if (item == bt->refvalue) {
        (*t) = nullptr;
    }
    else {
        (*t) = new Node<T>(item);
        assert((*t) != nullptr);
        CreateTree_1(bt, &((*t)->left));
        CreateTree_1(bt, &((*t)->right));
    }
}

template<typename T>
void Tree<T>::CreateTree_2(Tree<T>* bt, Node<T>*&t) {
    T item;
    std::cin >> item;
    if (item == bt->refvalue) {
        t = nullptr;
    }
    else {
        t = new Node<T>(item);
        assert(t != nullptr);
        CreateTree_2(bt, t->left);
        CreateTree_2(bt, t->right);
    }
}

template<typename T>
void Tree<T>::PreOrder(Tree<T>* bt) {
    PreOrder(bt->root);
    std::cout << std::endl;
}

template<typename T>
void Tree<T>::PreOrder(Node<T>* root) {
    if (root != nullptr) {
        std::cout << root->data << " ";
        PreOrder(root->left);
        PreOrder(root->right);
    }
}

template<typename T>
void Tree<T>::InOrder(Tree<T>* bt) {
    PreOrder(bt->root);
    std::cout << std::endl;
}

template<typename T>
void Tree<T>::InOrder(Node<T>* root) {
    if (root != nullptr) {
        InOrder(root->left);
        std::cout << root->data << " ";
        InOrder(root->right);
    }
}

template<typename T>
void Tree<T>::PostOrder(Tree<T>* bt) {
    PostOrder(bt->root);
    std::cout << std::endl;
}

template<typename T>
void Tree<T>::PostOrder(Node<T>* root) {
    if (root != nullptr) {
        PostOrder(root->left);
        PostOrder(root->right);
        std::cout << root->data << " ";
    }
}


template<typename T>
void Tree<T>::LevelOrder(Tree<T>* bt) {
    LevelOrder(bt->root);
    std::cout << std::endl;
}

template<typename T>
void Tree<T>::LevelOrder(Node<T>* root) {
    if(root != nullptr) {
        Node<T> *temp;
        std::queue<Node<T>*> Q;
        Q.push(root);
        while(!Q.empty()) {
            temp = Q.front();
            Q.pop();
            if(temp->left != nullptr) {
                Q.push(temp->left);
            }
            if(temp->right != nullptr) {
                Q.push(temp->right);
            }
            std::cout << temp->data << " ";
        }
    }
}

template<typename T>
int Tree<T>::Size(Tree<T>* bt) {
    return Size(bt->root);
}

template<typename T>
int Tree<T>::Size(Node<T>* root) {
    if(root == nullptr)
        return 0;
    return Size(root->left)+Size(root->right)+1;
}



#endif // BINARYTREE_H