C++非递归创建二叉树及非递归遍历二叉树

#include
#include
#include
using namespace std;

//节点类
class Node {
    friend class Tree;                              //将类Tree作为类Node的友元类,则类Tree能访问Node类的所有成员。
private:
    int key;                                        //关键字
    int status;                                     //节点的状态属性,默认为0代表未建立左右子树,1代表建立了左子树,2代表建立了左右子树。
    Node* lp;                                       //左指针
    Node* rp;                                       //右指针
                                                    //定义有参构造函数并初始化成员变量,参数为key值。
    Node(int k):key(k),status(0),lp(nullptr),rp(nullptr){}
};

//二叉树类
class Tree {
public:
    Tree():root(nullptr), lock(true) {}             //定义无参构造函数并初始化成员变量
    Node* create(const string&);                    //非递归创建二叉树
    void preOrder(Node*);                           //非递归前序遍历
    void inOrder(Node*);                            //非递归中序遍历
    void postOrder(Node*);                          //非递归后序遍历
    void leverOrder(Node*);                         //非递归层次遍历
    ~Tree() {}
private:
    stack s;                                 //用于先、中、后序遍历
    queue q;                                 //用于层次遍历
    bool lock;                                      //用于visit函数输出遍历结果显示遍历名称的一个锁变量
    Node* root;                                     //根节点
    typedef void(Tree::* Function_pointer)(Node*);  //声明一个指针函数,用于遍历,返回值为void,参数为Node*,指针函数名为Function_pointer
    void visit(Node* , Function_pointer);           //声明访问函数,第二个参数为指针函数
    
};

//创建二叉树
Node* Tree::create(const string& str) {
    auto it = str.begin();                          //返回指向字符串第一个字符的迭代器
                                                    //如果字符串为空或第一个字符为"#",返回root。
                                                    //注意,if条件中,str.empty()必须在左边,
                                                    //如果不在左边,当字符串为空时,*it解引用失败,引发异常。
    if (str.empty() || *it == '#') {
        return root;
    }
    Node* p = new Node(*it++);                      //创建新节点
    s.push(p);                                      //将根节点入栈
    root = p;                                       //root指向新节点
    while (it != str.end()) {                       //开始循环读取字符串,直到字符串最后一位。
        if (*it != '#' && p->status == 0) {         //判断下一个字符是否不等于"#"且上一个节点的状态为0
            p->lp = new Node(*it);                  //建立新节点,并将p指向的当前节点的左指针指向新节点
            p->status = 1;                          //更新p指向的当前节点的状态更新为1
            p = p->lp;                              //将p指针移动指向当前节点的左孩子节点
            s.push(p);                              //将新节点入栈
        }
        else if (*it == '#' && p->status == 0) {    //如果下一个字符是"#"且p指向的当前节点状态为0
            p->status = 1;                          //更新p指向的当前节点状态为1,说明当前节点的左子树已建立完成,左子树为空
        }
        else if (*it == '#' && p->status == 1) {    //如果下一个字符是"#"且p指向的当前节点状态为1
            p->status = 2;                          //更新p指向的当前节点状态为2,说明当前节点的右子树已建立完成,右子树为空
        }
        else if (*it != '#' && p->status == 1) {    //如果下一个字符不为"#"且当前节点的状态为1
            p->rp = new Node(*it);                  //建立新节点,并将p指向的当前节点的右指针指向新节点
            p->status = 2;                          //更新p指向的当前节点的状态为2
            p = p->rp;                              //将p指针移动指向当前节点的右孩子节点
            s.push(p);                              //将新节点入栈
        }
        while (p->status == 2) {                    //循环输出当前栈中状态为2的节点,状态为2的节点表明左右子树都建立完成,可出栈。
            p->status = 0;                          //出栈前先将栈顶结点状态更新为0
            s.pop();                                //开始出栈
            if (s.empty())                          //这里必须判断栈是否为空,如果栈为空了,p=s.top()语句就不用执行,否则会发生异常。
                break;                              //如果为空,跳出while
            p = s.top();                            //将p指针指向出栈后的当前栈中的栈顶结点
        }
        it++;                                       //移动到下一个字符位置
    }
    return root;                                    //返回根节点指针
}

//先序遍历
void Tree::preOrder(Node* root){
    Node* p = root;
    while (p || !s.empty()) {                       //p为真或栈不为空执行while
        if (p) {                                    //如果p指向当前节点为真
            visit(p, &Tree::preOrder);              //访问当前p指向的节点
            lock = false;                           //更新锁为假
            s.push(p);                              //将p指向的当前节点入栈
            p = p->lp;                              //p移动到p当前指向节点的左孩子节点
        }
        else {                                      //如果p指向当前节点的左孩子节点为空
            p = s.top()->rp;                        //p移动到当前栈顶节点的右孩子节点
            s.pop();                                //出栈当前栈顶节点
        }
    }
    lock = true;
}

//中序遍历
void Tree::inOrder(Node* root) {                    //同上
    Node* p = root;
    while (p || !s.empty()) {
        if (p) {
            s.push(p);
            p = p->lp;
        }
        else {
            visit(s.top(), &Tree::inOrder);
            lock = false;
            p = s.top()->rp;
            s.pop();
        }
    }
    lock = true;
}

//后序遍历
void Tree::postOrder(Node* root) {
    Node* p = root;
    while (p || !s.empty()) {                       
        if (p) {                                    //一直往左遍历直到左孩子为空
            p->status = 1;
            s.push(p);
            p = p->lp;
        }
        else {                                      //左孩子为空
            p = s.top();                            //p指向当前栈顶结点
            s.pop();                                //出栈当前栈顶结点
            if (p->status == 1) {                   //如果p指向的当前节点状态为1
                p->status = 2;                      //状态更新为2,表明可以visit访问了
                s.push(p);                          //再次将p指向的节点重新入栈
                p = p->rp;                          //p移动到p当前指向节点的右孩子
            }
            else {                                  //如果p当前指向的节点的状态为2
                p->status = 0;                      //置状态为0
                visit(p, &Tree::postOrder);         //访问节点
                lock = false;                       //置锁为假
                p = nullptr;                        //置p为空才能访问右子树,栈中栈顶结点。
            }
        }
    }
    lock = true;
}

//层次遍历
void Tree::leverOrder(Node* root) {
    if (!root)
        return;                                     //如果root为空返回
    Node* p = root;
    q.push(p);                                      //将根节点入栈
    while (!q.empty()) {
        p = q.front();                              //将p指向队首节点
        visit(p, &Tree::leverOrder);                //访问队首节点
        lock = false;
        q.pop();                                    //将队首节点出栈
        if (p->lp) {                                //如果队首节点的左孩子不为空
            q.push(p->lp);                          //左孩子入栈
        }
        if (p->rp) {                                //如果队首结点的右孩子不为空
            q.push(p->rp);                          //右孩子入栈
        }
    }
    lock = true;
}

//访问节点的函数
void Tree::visit(Node* p, Function_pointer fp){
    //第一次lock为真,判断函数指针指向的对应函数,
    //输出s遍历的名称,之后函数while循环体内lock设为假,不用再判断和输出s,
    //直到函数while结束后lock变为真,再执行if块中的语句,以此类推。
    if (lock) {
        string s;
        if      (fp == &Tree::preOrder)  { s = "前序遍历: "; }
        else if (fp == &Tree::inOrder)   { s = "中序遍历: "; }
        else if (fp == &Tree::postOrder) { s = "后序遍历: "; }
        else if (fp == &Tree::leverOrder){ s = "层次遍历: "; }
        else                             { s = "其它遍历: "; }
        cout << endl << endl << s;
    }
    cout << (char)p->key << " ";
}

void main() {
    string str = "ABDH##I##EJ###CF##G##";
    //删除字符串中所有空格
    str.erase(remove_if(str.begin(),str.end(),[](char c){ return(c == ' ');}),str.end());
    Tree t;
    auto root = t.create(str);
    if (root) {
        t.preOrder(root);
        t.inOrder(root);
        t.postOrder(root);
        t.leverOrder(root);
    }
    else {
        cout << "Tree is empty!" << endl;
    }
    cout << endl << endl;
    system("pause");
}

C++非递归创建二叉树及非递归遍历二叉树_第1张图片

 C++非递归创建二叉树及非递归遍历二叉树_第2张图片

你可能感兴趣的:(c++,数据结构,c语言)