非递归实现二叉树遍历(附c++完整代码)

本文详细介绍了二叉树的前序、中序和后序遍历算法,包括递归和非递归实现方式,通过具体代码示例帮助读者深入理解二叉树遍历的原理与实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:https://blog.youkuaiyun.com/happyjacob/article/details/83116702

先序、中序和后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同。


从图中可以看到,前序遍历在第一次遇见元素时输出,中序遍历在第二次遇见元素时输出,后序遍历在第三次遇见元素时输出。

非递归算法实现的基本思路:使用堆栈

一、前序遍历
1、递归实现
遍历过程为:

访问根结点;
先序遍历其左子树;
先序遍历其右子树。
void ProOrderTraverse(BiTree tree)
{
    if (tree == NULL)
        return;
    cout << tree->data << " ";
    ProOrderTraverse(tree->lchild);
    ProOrderTraverse(tree->rchild);
}
1
2
3
4
5
6
7
8
2、非递归实现
void ProOrder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    BiTree p = pRoot;
    stack<BiTree>s;

    while (p != NULL || !s.empty())
    {
        while (p != NULL)
        {
            s.push(p);
            cout << p->data << " ";
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
二、中序遍历
1、递归实现
遍历过程为:

中序遍历其左子树;
访问根结点;
中序遍历其右子树。
void midOrderTraverse(BiTree tree)
{
    if (tree == NULL)
        return;
    midOrderTraverse(tree->lchild);
    cout << tree->data << " ";
    midOrderTraverse(tree->rchild);
}
1
2
3
4
5
6
7
8
2、非递归实现
遇到一个结点,就把它压栈,并去遍历它的左子树;
当左子树遍历结束后,从栈顶弹出这个结点并访问它;
然后按其右指针再去中序遍历该结点的右子树。
void midOrder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    BiTree p = pRoot;
    stack<BiTree>s;
    while (p != NULL || !s.empty())
    {
        while (p!=NULL)
        {
            s.push(p);
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            cout << p->data << " ";        //第二次遇见的时候输出
            s.pop();
            p = p->rchild;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
三、后序遍历
1、递归实现
遍历过程为:

后序遍历其左子树;
后序遍历其右子树;
访问根结点。
void postOrderTraverse(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    postOrderTraverse(pRoot->lchild);
    postOrderTraverse(pRoot->rchild);
    cout << pRoot->data<<" ";
}
1
2
3
4
5
6
7
8
2、非递归实现
第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。

typedef struct Node
{
    BiTree btnode;
    bool isfirst;
}Node,*node;

void postOrder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    stack<node>s;
    BiTree p = pRoot;
    node tmp;
    while (p!=NULL || !s.empty())
    {
        while (p != NULL)            //沿左子树一直往下搜索,直至出现没有左子树的结点
        {
            node btn = (node)malloc(sizeof(Node));
            btn->btnode = p;
            btn->isfirst = true;
            s.push(btn);
            p = p->lchild;
        }
        if (!s.empty())
        {
            tmp = s.top();
            s.pop();
            if (tmp->isfirst == true)    //第一次出现在栈顶
            {
                tmp->isfirst = false;
                s.push(tmp);
                p = tmp->btnode->rchild;
            }
            else                //第二次出现在栈顶
            {
                cout << tmp->btnode->data<<" ";
                p = NULL;
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

void postorder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    stack<BiTree>s;
    BiTree cur = pRoot, pre = NULL;
    s.push(pRoot);
    while (!s.empty())
    {
        cur = s.top();
        if ((cur->lchild == NULL&&cur->rchild == NULL) ||
            ((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
        {
            cout << cur->data << " ";
            s.pop();
            pre = cur;
        }
        else
        {
            if (cur->rchild != NULL)
                s.push(cur->rchild);
            if (cur->lchild != NULL)
                s.push(cur->lchild);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
四、c++完整代码
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;
#define len 15                        //定义一个长度

typedef int ElemType;

typedef struct BiTNode
{
    ElemType data;
    struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

typedef struct Node
{
    BiTree btnode;
    bool isfirst;
}Node,*node;

//向下遍历,找到节点s应该插入的位置,节点有重复时,忽略这个节点
void SearchTreeNode(BiTree &root, BiTree &s)    //注意:使用引用传递
{
    if (root == NULL)
        return;
    if (s->data > root->data)
    {
        if (root->rchild == NULL)
        {
            root->rchild = s;
            return;
        }
        SearchTreeNode(root->rchild, s);//s值大于根节点值,未到达叶子节点,继续向右孩子遍历
    }

    else if (s->data < root->data)
    {
        if (root->lchild == NULL)
        {
            root->lchild = s;
            return;
        }
        SearchTreeNode(root->lchild, s);//s值小于根节点值,未到达叶子节点,继续向左孩子遍历
    }
}

//插入一个节点,树为空,插入节点即为根节点,否则找合适的位置插入
void InsertNode(BiTree &tree, BiTree &s)        //注意:使用引用传递
{
    if (tree == NULL)
        tree = s;
    else
        SearchTreeNode(tree, s);
}

//二叉排序树创建,每次增加一个结点,插到现有的二叉树上去
void CreateOrderBinaryTree(BiTree &tree, int *a)
{
    for (int i = 0; i < len; i++)
    {
        BiTree s = (BiTree)malloc(sizeof(BiTNode));
        s->data = a[i];
        s->lchild = NULL;
        s->rchild = NULL;
        InsertNode(tree, s);
    }
}
//前序遍历
void ProOrderTraverse(BiTree tree)
{
    if (tree == NULL)
        return;
    cout << tree->data << " ";
    ProOrderTraverse(tree->lchild);
    ProOrderTraverse(tree->rchild);
}
//非递归前序遍历
void ProOrder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    BiTree p = pRoot;
    stack<BiTree>s;

    while (p != NULL || !s.empty())
    {
        while (p != NULL)
        {
            s.push(p);
            cout << p->data << " ";        //第一次遇见的时候输出
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
}

//中序遍历
void midOrderTraverse(BiTree tree)
{
    if (tree == NULL)
        return;
    midOrderTraverse(tree->lchild);
    cout << tree->data << " ";
    midOrderTraverse(tree->rchild);
}

//非递归中序遍历
void midOrder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    BiTree p = pRoot;
    stack<BiTree>s;
    while (p != NULL || !s.empty())
    {
        while (p!=NULL)
        {
            s.push(p);
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            cout << p->data << " ";        //第二次遇见的时候输出
            s.pop();
            p = p->rchild;
        }
    }
}

//后序遍历
void postOrderTraverse(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    postOrderTraverse(pRoot->lchild);
    postOrderTraverse(pRoot->rchild);
    cout << pRoot->data<<" ";
}

//非递归实现后续遍历
void postOrder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    stack<node>s;
    BiTree p = pRoot;
    node tmp;
    while (p!=NULL || !s.empty())
    {
        while (p != NULL)        //沿左子树一直往下搜索,直至出现没有左子树的结点
        {
            node btn = (node)malloc(sizeof(Node));
            btn->btnode = p;
            btn->isfirst = true;
            s.push(btn);
            p = p->lchild;
        }
        if (!s.empty())
        {
            tmp = s.top();
            s.pop();
            if (tmp->isfirst == true)            //第一次出现在栈顶
            {
                tmp->isfirst = false;
                s.push(tmp);
                p = tmp->btnode->rchild;
            }
            else                        //第二次出现在栈顶
            {
                cout << tmp->btnode->data<<" ";
                p = NULL;
            }
        }
    }
}

//非递归实现后续遍历
void postorder(BiTree pRoot)
{
    if (pRoot == NULL)
        return;
    stack<BiTree>s;
    BiTree cur = pRoot, pre = NULL;
    s.push(pRoot);
    while (!s.empty())
    {
        cur = s.top();
        if ((cur->lchild == NULL&&cur->rchild == NULL) ||
            ((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
        {
            cout << cur->data << " ";
            s.pop();
            pre = cur;
        }
        else
        {
            if (cur->rchild != NULL)
                s.push(cur->rchild);
            if (cur->lchild != NULL)
                s.push(cur->lchild);
        }
    }
}

int main()
{
    int a[len] = { 62, 88, 58, 47, 35, 73, 51, 99, 37, 93, 23, 27, 45, 21, 12 };

    BiTree tree = NULL;
    //创建一个二叉树,并中序遍历
    CreateOrderBinaryTree(tree, a);

    cout << "前序遍历" << endl;
    ProOrderTraverse(tree);
    cout << endl;
    ProOrder(tree);
    cout << endl<<endl;

    cout << "中序遍历" << endl;
    midOrderTraverse(tree);
    cout << endl;
    midOrder(tree);
    cout << endl<<endl;

    cout << "后序遍历" << endl;
    postOrderTraverse(tree);
    cout << endl;
    postOrder(tree);
    cout << endl;
    postorder(tree);
    cout << endl<<endl;

    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值