#include <iostream>
#include <string>
#include <cinttypes>
#include <iomanip>
#include <map>
#include <stack>
#include <vector>
#include <deque>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::setw;
using std::setfill;
using std::map;
using std::stack;
using std::vector;
using std::deque;

template <typename T>
struct _BiTreeNode
{
    T data;

    int height;

    int position;
    int splice;
    
    struct _BiTreeNode *lchild;
    struct _BiTreeNode *rchild;
};

template <typename T>
class BiTree
{
private:
    using BiTreeNodeType =     struct _BiTreeNode<T> *;
public:
    BiTree()
    {
        m_bi_tree = nullptr;
        m_bi_tree_depth = 0;
        m_data_index = 0;

        /*填充数据*/
        FillData();
        
//        cout << "Please input root:";
//        CreatCinBitree(m_bi_tree, 0);
        /*创建二叉树*/
        CreatBitree(m_bi_tree, 0);

        /*打印树*/
        PromptExistBiTree();

        /*前序遍历*/
        Pre_recursive_order(m_bi_tree);
        Pre_non_recursive_order();

        /*中序遍历*/
        In_recursive_order(m_bi_tree);
        In_non_recursive_order();

        /*后序遍历*/
        After_recursive_order(m_bi_tree);
        After_non_recursive_order();

        /*层次遍历和深度遍历*/
        Tree_Level_order();
        Tree_Depth_order();
    }
    
    ~BiTree()
    {
        Destory(m_bi_tree);
    }

private:

    void Tree_Level_order()
    {
        using Deque_Node_Type = struct _BiTreeNode<T> *;
        deque<Deque_Node_Type> s_bi_tree;

        Deque_Node_Type p = m_bi_tree;
        if (p == nullptr)
        {
            return;
        }

        s_bi_tree.push_back(p);

        while (!s_bi_tree.empty())
        {
            p = s_bi_tree.front();

            cout << p->data << " ";
            
            if (p->lchild != nullptr)
            {
                s_bi_tree.push_back(p->lchild);
            }

            if (p->rchild != nullptr)
            {
                s_bi_tree.push_back(p->rchild);
            }

            s_bi_tree.pop_front();
        }

        cout << endl;
    }

    void Tree_Depth_order()
    {
        using Stack_Node_Type = struct _BiTreeNode<T> *;
        stack<Stack_Node_Type> s_bi_tree;

        Stack_Node_Type p = m_bi_tree;
        if (p == nullptr)
        {
            return;
        }

        s_bi_tree.push(p);

        while (!s_bi_tree.empty())
        {
            p = s_bi_tree.top();

            cout << p->data << " ";
            s_bi_tree.pop();
            
            if (p->rchild != nullptr)
            {
                s_bi_tree.push(p->rchild);
            }

            if (p->lchild != nullptr)
            {
                s_bi_tree.push(p->lchild);
            }
        }

        cout << endl;
    }

    /*前中后序 递归和非递归遍历*/
    void Pre_recursive_order(BiTreeNodeType &bi_tree)
    {
        cout << bi_tree->data << " ";
        if (bi_tree->lchild != nullptr)
        {
            Pre_recursive_order(bi_tree->lchild);
        }

        if (bi_tree->rchild != nullptr)
        {
            Pre_recursive_order(bi_tree->rchild);
        }

        if (bi_tree == m_bi_tree)
        {
            cout << endl;
        }
    }

    void In_recursive_order(BiTreeNodeType &bi_tree)
    {
        if (bi_tree->lchild != nullptr)
        {
            In_recursive_order(bi_tree->lchild);
        }

        cout << bi_tree->data << " ";

        if (bi_tree->rchild != nullptr)
        {
            In_recursive_order(bi_tree->rchild);
        }

        if (bi_tree == m_bi_tree)
        {
            cout << endl;
        }
    }

    void After_recursive_order(BiTreeNodeType &bi_tree)
    {
        if (bi_tree->lchild != nullptr)
        {
            After_recursive_order(bi_tree->lchild);
        }

        if (bi_tree->rchild != nullptr)
        {
            After_recursive_order(bi_tree->rchild);
        }

        cout << bi_tree->data << " ";

        if (bi_tree == m_bi_tree)
        {
            cout << endl;
        }
    }

    void Pre_non_recursive_order()
    {
        using Stack_Node_Type = struct _BiTreeNode<T> *;
        stack<Stack_Node_Type> s_bi_tree;

        Stack_Node_Type p = m_bi_tree;

        while ((p != nullptr) || (!s_bi_tree.empty()))
        {
            while (p != nullptr)
            {
                cout << p->data << " ";
                s_bi_tree.push(p);
                p = p->lchild;
            }

            if (!s_bi_tree.empty())
            {
                p = s_bi_tree.top();
                s_bi_tree.pop();
                p = p->rchild;
            }
        }

        cout << endl;
    }

    
    void In_non_recursive_order()
    {
        using Stack_Node_Type = struct _BiTreeNode<T> *;
        stack<Stack_Node_Type> s_bi_tree;

        Stack_Node_Type p = m_bi_tree;

        while ((p != nullptr) || (!s_bi_tree.empty()))
        {
            while (p != nullptr)
            {
                s_bi_tree.push(p);
                p = p->lchild;
            }

            if (!s_bi_tree.empty())
            {
                p = s_bi_tree.top();
                cout << p->data << " ";
                s_bi_tree.pop();
                p = p->rchild;
            }
        }

        cout << endl;
    }

    void After_non_recursive_order()
    {
        using Stack_Node_Type = struct _BiTreeNode<T> *;
        stack<Stack_Node_Type> s_bi_tree;
        vector<T> visit_data;

        Stack_Node_Type p = m_bi_tree;

        while ((p != nullptr) || (!s_bi_tree.empty()))
        {
            while (p != nullptr)
            {
                s_bi_tree.push(p);
                p = p->lchild;
            }

            if (!s_bi_tree.empty())
            {
                p = s_bi_tree.top();
                if ((p->rchild == nullptr) || ((p->rchild != nullptr) && HaveVisited(p->rchild->data, visit_data)))
                {
                    visit_data.push_back(p->data);
                    s_bi_tree.pop();
                    p = nullptr;
                }
                else
                {
                    p = p->rchild;
                }
            }
        }

        for (auto vec_node : visit_data)
        {
            cout << vec_node << " ";
        }
        cout << endl;
    }

    bool HaveVisited(T data, vector<T> &data_vec)
    {
        for (auto vec_node : data_vec)
        {
            if (vec_node == data)
            {
                return true;
            }
        }

        return false;
    }

    void FillData()
    {
        m_data[0] = "-";
        m_data[1] = "+";
        m_data[2] = "a";
        m_data[3] = "#";
        m_data[4] = "#";
        m_data[5] = "*";
        m_data[6] = "b";
        m_data[7] = "#";
        m_data[8] = "#";
        m_data[9] = "-";
        m_data[10] = "c";
        m_data[11] = "#";
        m_data[12] = "#";
        m_data[13] = "d";
        m_data[14] = "#";
        m_data[15] = "#";
        m_data[16] = "/";
        m_data[17] = "e";
        m_data[18] = "#";
        m_data[19] = "#";
        m_data[20] = "f";
        m_data[21] = "#";
        m_data[22] = "#";
    }

    void PromptExistBiTree()
    {
        m_level_str_map.clear();
        MarkBinaryTree(m_bi_tree, GetRootPosition(m_bi_tree_depth));
        SpliceBiTreeStr(m_bi_tree);

        PaintBiTree();
    }

    void CreatCinBitree(BiTreeNodeType &bi_tree, int height)
    {
        T data;
        cin >> data;

        if (data == "#")
        {
            bi_tree = nullptr;
        }
        else
        {
            bi_tree = new struct _BiTreeNode<T>;

            bi_tree->data = data;
            bi_tree->height = height;
            if (height > m_bi_tree_depth)
            {
                m_bi_tree_depth = height;
            }

            bi_tree->position = 0;
            bi_tree->splice = 0;
            bi_tree->lchild = nullptr;
            bi_tree->rchild = nullptr;

            PromptExistBiTree();

            cout << "Please input " << data << " left child:";
            CreatCinBitree(bi_tree->lchild, height + 1);
            cout << "Please input " << data << " right child:";
            CreatCinBitree(bi_tree->rchild, height + 1);
        }
    }

    void CreatBitree(BiTreeNodeType &bi_tree, int height)
    {
        if (m_data_index > 22)
        {
            return;
        }

        cout << "m_data[" << m_data_index << "]=" << m_data[m_data_index] << endl;
        
        if (m_data[m_data_index] == "#")
        {
            m_data_index++;
            bi_tree = nullptr;
        }
        else
        {
            bi_tree = new struct _BiTreeNode<T>;

            bi_tree->data = m_data[m_data_index];
            bi_tree->height = height;
            if (height > m_bi_tree_depth)
            {
                m_bi_tree_depth = height;
            }

            bi_tree->position = 0;
            bi_tree->splice = 0;
            bi_tree->lchild = nullptr;
            bi_tree->rchild = nullptr;

            m_data_index++;

            CreatBitree(bi_tree->lchild, height + 1);
            CreatBitree(bi_tree->rchild, height + 1);
        }
    }

    void Destory(BiTreeNodeType &bi_tree)
    {
        if (bi_tree)
        {
            Destory(bi_tree->lchild);
            Destory(bi_tree->rchild);

            delete bi_tree;
            bi_tree = NULL;
        }
    }

    void SpliceBiTreeStr(BiTreeNodeType &bi_tree)
    {
        if (bi_tree != nullptr)
        {
            string p_str = FindLevelStr(bi_tree->splice);

            if (!p_str.empty())    
            {                
                p_str.append(bi_tree->position - p_str.size(), ' ');
            }
            else
            {            
                p_str.append(bi_tree->position, ' ');
            }

            p_str.append(bi_tree->data);                
            m_level_str_map[bi_tree->splice] = p_str;
            
#if 1
            if (bi_tree->height != m_bi_tree_depth)
            {
                int brance_splice = GetRootPosition(m_bi_tree_depth - bi_tree->height - 1);
                for (int i=1; i<=brance_splice; ++i)
                {
                    string brance_str = FindLevelStr(bi_tree->splice - i);
                    
                    if (!brance_str.empty())
                    {
                        brance_str.append(bi_tree->position - brance_str.size() - i, ' ');    
                    }
                    else
                    {
                        brance_str.append(bi_tree->position - i, ' ');
                    }

                    if (bi_tree->lchild != nullptr)
                    {
                        brance_str.append("/");
                    }
                    else
                    {
                        brance_str.append(" ");
                    }


                    if (bi_tree->rchild != nullptr)
                    {
                        brance_str.append(i*2 - 1, ' ');
                        brance_str.append("\\");
                    }
                                            
                    m_level_str_map[bi_tree->splice - i] = brance_str;
                }
            }
#endif
            if (bi_tree->lchild != nullptr)
            {
                SpliceBiTreeStr(bi_tree->lchild);
            }

            if (bi_tree->rchild != nullptr)
            {
                SpliceBiTreeStr(bi_tree->rchild);
            }
        }
    }

    void MarkBinaryTree(BiTreeNodeType &bi_tree, int position)
    {
        if (bi_tree == nullptr)
        {
            return;
        }

        bi_tree->position = position;
        bi_tree->splice = GetRootSplice(m_bi_tree_depth - bi_tree->height);
    
//        cout << bi_tree->height << ":" << bi_tree->splice << ":" << bi_tree->position << ":" << bi_tree->data << endl;

        if (bi_tree->lchild != nullptr)
        {
            MarkBinaryTree(bi_tree->lchild, position - GetRootPosition(m_bi_tree_depth - bi_tree->height - 1) - 1);
        }

        if (bi_tree->rchild != nullptr)
        {
            MarkBinaryTree(bi_tree->rchild, position + GetRootPosition(m_bi_tree_depth - bi_tree->height - 1) + 1);
        }
    }

    void PaintBiTree()
    {
        int splice = -1;
        while ((splice = SelectLowestNode()) != -1)
        {
            cout << m_level_str_map[splice] << endl;
            m_level_str_map.erase(splice);
        }
    }

    int SelectLowestNode()
    {
        int mininal_num = -1;
        for (auto map_pair : m_level_str_map)
        {
            if (map_pair.first > mininal_num)
            {
                mininal_num = map_pair.first;
            }
        }

        return mininal_num;
    }


    int GetRootPosition(int height)
    {
        return abs(GetPrintSide(height, 1) * 3 - 1);
    }

    int GetRootSplice(int height)
    {
        int splice_num = GetPrintSide(height, 1) * 3 - 1;
        return (splice_num > 0) ? splice_num : 0;
    }

    int GetPrintSide(int height, int side)
    {
        if (height <= 0)
        {
            return 0;
        }
        else if (height == 1)
        {
            return side;
        }
        else
        {
            return GetPrintSide(height-1, side*2);
        }
    }

    string FindLevelStr(int splice)
    {
        string tmp_str;
        for (auto node : m_level_str_map)
        {
            if (node.first == splice)
            {
                return node.second;
            }
        }

        return tmp_str;
    }

private:
    struct _BiTreeNode<T> *m_bi_tree;
    int m_bi_tree_depth;

    int m_data_index;

    T m_data[128];

    map<int, string> m_level_str_map;
};

int main()
{

    BiTree<string> cc_b_tree;

    return 0;
}