二叉树的三种递归与非递归遍历算法

树结点的声明

struct BinaryNode
{
    char element;
    BinaryNode* left;
    BinaryNode* right;
    BinaryNode()
    {
        element = ' ';
        left = right = NULL;
    }
};

创建一棵二叉树

BinaryNode * creatBinaryTree (string&s)
{
    if (s.empty())
        return NULL;
    size_t n = s.size();
    BinaryNode* p = new BinaryNode[n];
    for (int i = 0; i < n; ++i)
    {
        p[i].element = s[i];
        if ( (2*i+1) < n )
            p[i].left = &p[2*i+1];
        if ( (2*i+2) < n )
            p[i].right = &p[2*i+2];
    }
    return p;
}

输出二叉树

enum mode{preR,preNr, inR, inNr, postR, postNr};

void displayBinaryTree(BinaryNode*t, enum mode& m)
{
    switch(m)
    {
    case preR:
        preOrderTraverse_Recursive(t);
        break;
    case preNr:
        preOrderTraverse_nonRecursive(t);
        break;
    case inR:
        inOrderTraverse_Recursive(t);
        break;
    case inNr:
        inOrderTraverse_nonRecursive(t);
        break;
    case postR:
        postOrderTraverse_Recursive(t);
        break;
    case postNr:
        postOrderTraverse_nonRecursive(t);
        break;
    default:
        ;
    }
}

一.先序遍历

1.递归算法

void preOrderTraverse_Recursive( BinaryNode *t)
{
    if (t)
    {
        cout << t->element << endl;
        preOrderTraverse_Recursive(t->left);
        preOrderTraverse_Recursive(t->right);
    }
}

2.非递归算法
思路::在先序遍历中,由于根节点首先被访问,而且由根结点可以同时得到左右孩子结点的信息,因此在访问过程中,可以在访问根节点的同时将根节点从栈中删除,并且将根节点的左右孩子按照右孩子,左孩子的顺序入栈。

void preTraverse_nonRecursive( BinaryNode *t)
{
        stack<TreeNode*>s;
        TreeNode* p = root;
        s.push(p);     
        while (!s.empty())
        {
            p = s.top();
            s.pop();
            if (p)
            {
                cout<<p->element<<endl;
                s.push(p->right);
                s.push(p->left);
            }
        }
}

二.中序遍历

1.递归算法

void inOrderTraverse_Recursive( BinaryNode *t)
{
    if (t)
    {
        inOrderTraverse_Recursive(t->left);
        cout << t->element << endl;
        inOrderTraverse_Recursive(t->right);
    }
}

2.非递归算法
思路1和思路2的主要区别是思路1会将空指针压入栈中,而思路2则不会,因此思路1需要将空指针弹出栈

//思路1
void inOrderTraverse_nonRecursive( BinaryNode *t)
{
    stack<BinaryNode*>s;
    BinaryNode* p = t ;
    s.push(p);
    while ( !s.empty() )
    {//p表示栈顶元素
        p = s.top();
        while ( p  )
        {//向左走到尽头,最后压入的一定是空指针
            p = p->left;
            s.push(p);
        }
        s.pop();//空指针出栈
        if (!s.empty())
        {
            p = s.top();
            s.pop();
            cout << p->element << endl;
            s.push( p->right );
        }
    }
}
void inOrderTraverse_nonRecursive( BinaryNode *t)
{//思路2
    stack<BinaryNode*>s;
    BinaryNode* p = t ;
    while ( p || !s.empty() )
    {//p指向的是下一个需要被访问的结点
        if ( p )
        {
            s.push(p);
            p = p->left;
        }
        else
        {//p为null,栈非空
            p = s.top();
            s.pop();//根指针退栈,遍历右子树
            cout << p->element << endl;
            p = p->right;
        }
    }
}

三.后序遍历

1.递归算法

void postOrderTraverse_Recursive( BinaryNode *t)
{
    if (t)
    {
        postOrderTraverse_Recursive(t->left);
        postOrderTraverse_Recursive(t->right);
        cout << t->element << endl;
    }
}

2.非递归算法
思路:按照根节点,右孩子结点,左孩子结点的顺序依次入栈。如果一个结点没有左右孩子结点,则该结点可被访问,同时该结点出栈。如果一个结点有左右孩子结点,但是其孩子结点已经被访问,则该结点也可以被访问。因此需要设置一个变量preNode存放上次被访问的结点。

void postOrderTraverse_nonRecursive( BinaryNode *t)
{
        stack<BinaryNode*>s;
        BinaryNode* p = t ;
        BinaryNode* preNode = t;
        if (p)
            s.push(p);
        while (!s.empty())
        {
            p = s.top();
            if ( (p->left == NULL && p->right==NULL) 
                || (preNode == p->left || preNode == p->right) )
            {
                cout << p->element << endl;
                s.pop();
                preNode = p;
            }
            else
            {
                if (p->right)
                    s.push(p->right);
                if (p->left)
                    s.push(p->left);
            }
        }
}

后序遍历时栈的出栈入栈情况如图所示:结点d因为左右孩子都为空,因此可以访问,访问完成后出栈,结点b的左右孩子因为都被访问过也可以被访问,此时b的前一个访问结点是结点e,它的右结点。
上图为反映了后序遍历时数据出栈入栈的情况。结点d因为左右孩子都为空,因此可以访问,访问完成后出栈,结点b的左右孩子因为都被访问过,因此也可以被访问,此时b的前一个访问结点是结点e,即它的右结点。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值