二叉树的创建|非递归遍历

创建

struct BinaryTree
{
    T key;
    BinaryTree* lchild;
    BinaryTree* rchild;
    bool IsSecondPop=false; //主要是方便后序遍历时是否第二次进栈
};

BinaryTree* CreateBinaryTree()   //先序建树 若碰到‘#’就是表示为空,如果不是空,就先建左子树,后建立右子树
{
    T in;
    cin >> in;
    BinaryTree *p = new BinaryTree();
    if (in=='#')
    {
        p = NULL;
        return p;
    }


    else 
    {
        p->key = in;
        p->lchild = CreateBinaryTree();
        p->rchild = CreateBinaryTree();
    }
    return p;
}

前序遍历:

借助栈。
判断当前节点是否为空,否,把当前节点压入栈,访问该节点,并左路下降pnode指向pnode->left
若为空,指向右子树(pnode->right),弹出栈顶元素。

void preOrdernorecursion(BinaryTree* pnode)  
{


    if (pnode == nullptr)
        return;
    stack <BinaryTree*> A;

    while (pnode || !A.empty())
    {
        if (pnode)
        {
            cout << pnode->key << endl;
            A.push(pnode);
            pnode = pnode->lchild;

        }
        else
        {
            pnode = A.top()->rchild;
            A.pop();

        }
    }
}

中序遍历:

借助栈。 判断是否为空,否,把当前节点压入栈,并左路下降pnode指向pnode->left 。
若为空,取栈顶元素,访问该元素节点,并指向右子树(pnode->right),弹出栈顶元素。

void InOrdernorecursion(BinaryTree* pnode)
{
    if (pnode == nullptr)
        return;
    stack <BinaryTree*> A;

    while (pnode || !A.empty())
    {

        if (pnode)
        {
            A.push(pnode);
            pnode = pnode->lchild;
        }
        else
        {
            cout << A.top()->key << endl;
            pnode = A.top()->rchild;
            A.pop();
        }

    }
}
  • 前序和中序都是左子树非空左路下降同时压栈,若为空转向右子树,同时弹栈。
  • 区别就是何时访问节点元素,前序是在压入的时候同时访问,而中序是在弹出的时候访问。

后序遍历:

一个节点会入两次栈,左路下降的时候第一次入栈,直到为空,弹出当前节点,这是第一次出栈,然后直接再压进去栈,之后判断其右子树,然后继续入栈。如果右子树也为空了,此时第二次弹出,弹出的同时访该节点。

void PostOrdernorecursion(BinaryTree* pnode)
{
    if (pnode == nullptr)
        return;
    stack <BinaryTree*> mystack;
    BinaryTree *flagpNode;
    while (pnode || !mystack.empty())
    {
        while (pnode)
        {
            flagpNode= pnode;
            //flagpNode.IsSecondPop = false;   //第一次进栈
            mystack.push(flagpNode);
            pnode = pnode->lchild;
        }
        flagpNode = mystack.top();         //左边没有左子树了,就要出栈了
        mystack.pop(); //第一次出栈
        if (!flagpNode->IsSecondPop) //如果是第一次出栈,就把它再压进去,因为要判断右边还有没有子树
        {
            flagpNode->IsSecondPop = true;  //把进栈bool设为true
            mystack.push(flagpNode);
            pnode = flagpNode->rchild;   //转到右子树
        }
        else   //如果是第二次出栈,就访问它
        {
            cout << flagpNode->key << endl;
        }

    }

}

如果要求不能改变二叉树的结构,则需要自己从新构造一个具有判断是否第二次进栈bool变量的新结构体。如下:

void PostOrdernorecursion(BinaryTree* pnode)
{
    if (pnode == nullptr)
        return;
    struct FlagBT   //自己设立的结构体
    {
        BinaryTree* p;
        bool issecondpop;
    };
    stack <FlagBT> mystack;
    FlagBT flagpNode;
    while (pnode||!mystack.empty())
    {
        while (pnode)
        {
            flagpNode.p = pnode;
            flagpNode.issecondpop = false;   //第一次进栈
            mystack.push(flagpNode);         
            pnode = pnode->lchild;
        }
        flagpNode = mystack.top();         //左边没有左子树了,就要出栈了
        mystack.pop(); //第一次出栈
        if (!flagpNode.issecondpop) //如果是第一次出栈,就把它再压进去,因为要判断右边还有没有子树
        {
            flagpNode.issecondpop = true;  //把进栈bool设为true
            mystack.push(flagpNode);
            pnode = flagpNode.p->rchild;
        }
        else   //如果是第二次出栈,就访问它
        {
            cout << flagpNode.p->key << endl;
        }

    }

}

层次遍历:

借助队列:

void BreadthOrder(BinaryTree* pnode)
{

    if (pnode == nullptr)
        return;
    queue <BinaryTree*> A;
    A.push(pnode);
    while (pnode)
    {
        cout << pnode->key << endl;
        if (pnode->lchild)A.push(pnode->lchild);
        if (pnode->rchild)A.push(pnode->rchild);
        A.pop();

        if (!A.empty()) pnode = A.front();
        else pnode = nullptr;
    }
}

但是很多有分层输出的要求,需要记录每一层的终点,待补充……
还是需要一个队列来记录,但是在每一层一开始会根据当前队列的大小来标记为last,当小于这个last时,把这层的节点打印出来,然后这个节点弹出队列,同时把他的左右孩子压入队列中。这样没打印出新的一层,这一层的节点都弹出了队列,同时下一层(这一层的左右孩子)又压入队列,周而复始,直到队列为空。

vector<vector<BinaryTree*>>  BreadthOrder_Layer(BinaryTree* pnode)
{
    vector<vector<BinaryTree*>> res;

    if (pnode == nullptr)
        return res;
    queue <BinaryTree*> q;
    q.push(pnode);           //先把根节点压入队列

    while (!q.empty())
    {
        vector <BinaryTree*> layer;      //这一层的节点数组
        int cur = 0;                     //遍历标记
        int last = q.size();             //结束遍历标记

        while (cur++ < last)
        {
            BinaryTree* s = q.front();  //队列先入先出
            layer.push_back(s);         //把这个节点压入当前层的数组           
            //cout << s->key << ' ';
            q.pop();                    //压入layer后在队列中弹出     

            if (s->lchild)q.push(s->lchild);  //左右孩子压入
            if (s->rchild)q.push(s->rchild);

        }
        res.push_back(layer);          //当前层压入结果数组
        //cout << endl;
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值