二叉树的建造、递归与非递归遍历

本文介绍如何根据前序、中序及后序遍历序列构造二叉树,并实现递归与非递归方式的前序、中序、后序及层序遍历。通过代码示例详细解析了每种遍历方法的具体实现。

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

#include "stdafx.h"
#include <iostream>
#include <stack>
#include <queue>
#include <Windows.h>
using namespace std;

typedef struct _Node
{
    int data;
    struct _Node *left;
    struct _Node *right;
    bool isVisit;        //用于后序非递归遍历,表示节点是否可以访问
    _Node()
    {
        data = 0;
        left = NULL;
        right = NULL;
        isVisit = false;
    }
}Node, *PNode;

//****************二叉树的递归建造********************
//约定:输入0表示该节点的子树为NULL
void RecurCreate(PNode pRoot)
{
    int data;
    cin>>data;
    if (0 != data)
    {
        pRoot = new Node;
        pRoot->data = data;
        RecurCreate(pRoot->left);
        RecurCreate(pRoot->right);
    } 
}

//假定二叉树如下图所示,利用前序和中序、后序与中序可以唯一确定一棵二叉树的原理
//                       1
//                     /   \
//                    2     3
//                  / \     / \
//                 4   5   6   7 
//               / \  /
//              8   9 10

const int MAX_NUM = 10;                             //二叉树的节点数
int pre[MAX_NUM] = {1, 2, 4, 8, 9, 5, 10, 3, 6, 7}; //前序遍历的数组
int mid[MAX_NUM] = {8, 4, 9, 2, 10, 5, 1, 6, 3, 7}; //中序遍历的数组
int post[MAX_NUM] = {8, 9, 4, 10, 5, 2, 6, 7,3, 1}; //后序遍历的数组

//获取前序数组的data在中序数组的索引
int GetPositionInMid(int data)
{
    for (int i = 0; i < MAX_NUM; i++)
    {
        if (mid[i] == data)
        {
            return i;
        }
    }
}

//利用前序和中序可以唯一确定一棵二叉树
//参数说明
// pRoot   —— 需要建造节点的指针引用
// iPre    —— 表示pRoot节点的左子树(右子树)在前序数组的第一个索引
// iMid    —— 表示pRoot节点的左子树(右子树)在中序数组的第一个索引
// length  —— 表示pRoot节点的左子树(右子树)的长度
void PreAndMidRecurCreate(PNode &pRoot, int iPre, int iMid, int length)
{
    if (length <= 0)
    {
        return;
    }
    pRoot = new Node;
    pRoot->data = pre[iPre];
    int pos = GetPositionInMid(pre[iPre]);
    PreAndMidRecurCreate(pRoot->left, iPre + 1, iMid, pos - iMid);
    PreAndMidRecurCreate(pRoot->right, iPre + (pos - iMid) + 1, pos + 1, length - (pos - iMid) - 1);
}

//利用后序和中序可以唯一确定一棵二叉树
//参数说明
// pRoot   —— 需要建造节点的指针引用
// iPost   —— 表示pRoot节点的左子树(右子树)在后序数组的第一个索引
// iMid    —— 表示pRoot节点的左子树(右子树)在中序数组的第一个索引
// length  —— 表示pRoot节点的左子树(右子树)的长度
void PostAndMidRecurCreate(PNode &pRoot, int iPost, int iMid, int length)
{
    if (length <= 0)
    {
        return;
    }
    pRoot = new Node;
    pRoot->data = post[iPost];
    int pos = GetPositionInMid(post[iPost]);
    PostAndMidRecurCreate(pRoot->left, iPost - 1 - (length - (pos - iMid) - 1), iMid, pos - iMid);
    PostAndMidRecurCreate(pRoot->right, iPost - 1, pos + 1, length - (pos - iMid) - 1);
}


//****************二叉树的递归遍历********************

//前序递归遍历
void PreRecurTraversal(PNode pRoot)
{
    if (NULL != pRoot)
    {
        cout<<pRoot->data<<'\t';
        PreRecurTraversal(pRoot->left);
        PreRecurTraversal(pRoot->right);
    }
}

//中序递归遍历
void MidRecurTraversal(PNode pRoot)
{
    if (NULL != pRoot)
    {
        MidRecurTraversal(pRoot->left);
        cout<<pRoot->data<<'\t';
        MidRecurTraversal(pRoot->right);
    }
}

//序后递归遍历
void PostRecurTraversal(PNode pRoot)
{
    if (NULL != pRoot)
    {
        PostRecurTraversal(pRoot->left);
        PostRecurTraversal(pRoot->right);
        cout<<pRoot->data<<'\t';
    }
}

//****************二叉树的非递归遍历********************

//第一种前序非递归遍历
void PreTraversalOne(PNode pRoot)
{
    PNode pTree = pRoot;
    stack<PNode> s;
    while (!s.empty() || NULL != pTree)
    {
        while (NULL != pTree)
        {
            cout<<pTree->data<<'\t';
            s.push(pTree);
            pTree = pTree->left;
        }
        if (!s.empty())
        {
            pTree = s.top();
            s.pop();
            pTree = pTree->right;
        }
    }
}

//第二种前序非递归遍历
void PreTraversalTwo(PNode pRoot)
{
    PNode pTree = pRoot;
    stack<PNode> s;
    s.push(pTree);
    while (!s.empty())
    {
        pTree = s.top();
        cout<<pTree->data<<'\t';
        s.pop();
        if (NULL != pTree->right) //1、右子树进栈
        {
            s.push(pTree->right);
        }
        if (NULL != pTree->left) //2、左子树进栈
        {
            s.push(pTree->left);
        }
    }
}

//中序非递归遍历
void MidTraversal(PNode pRoot)
{
    PNode pTree = pRoot;
    stack<PNode> s;
    while (!s.empty() || NULL != pTree)
    {
        while (NULL != pTree)
        {
            s.push(pTree);
            pTree = pTree->left;
        }
        if (!s.empty())
        {
            pTree = s.top();
            cout<<pTree->data<<'\t';
            s.pop();
            pTree = pTree->right;
        }
    }
}

//后序非递归遍历
void PostTraversal(PNode pRoot)
{
    PNode pTree = pRoot;
    stack<PNode> s;
    while (!s.empty() || NULL != pTree)
    {
        while (NULL != pTree)
        {
            s.push(pTree);
            pTree = pTree->left;
        }
        if (!s.empty())
        {
            pTree = s.top();
            if (pTree->isVisit)
            {
                cout<<pTree->data<<'\t';
                s.pop();
                pTree = NULL;
            }
            else
            {
                pTree->isVisit = true;
                pTree = pTree->right;
            }
        }
    }
}

//层序非递归遍历——用队列,注意与第二种非递归前序遍历的区别
void LevelTraversal(PNode pRoot)
{
    PNode pTree = pRoot;
    queue<PNode> q;
    q.push(pTree);
    while (!q.empty())
    {
        pTree = q.front();
        q.pop();
        cout<<pTree->data<<'\t';
        if (NULL != pTree->left)  //1、左子树进队列
        {
            q.push(pTree->left);
        }
        if (NULL != pTree->right) //2、右子树进队列
        {
            q.push(pTree->right);
        }
    }
}

//辅助函数,设置控制台的颜色
void SetConsoleTextColor(WORD dwColor)
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (INVALID_HANDLE_VALUE == handle)
    {
        return;
    }
    SetConsoleTextAttribute(handle, dwColor);
}

int _tmain(int argc, _TCHAR* argv[])
{
    PNode pRoot1 = NULL;
    PNode pRoot2 = NULL;

    cout<<endl<<"******************根据前序和中序建造二叉树********************"<<endl<<endl;
    PreAndMidRecurCreate(pRoot1, 0, 0, MAX_NUM);
    
    SetConsoleTextColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    cout<<endl<<"******************层序遍历二叉树********************"<<endl<<endl;
    LevelTraversal(pRoot1);
    SetConsoleTextColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    cout<<endl<<"******************递归遍历二叉树********************"<<endl<<endl;
    cout<<endl<<"       **********前序递归遍历二叉树**********"<<endl<<endl;
    PreRecurTraversal(pRoot1);
    cout<<endl<<"       **********中序递归遍历二叉树**********"<<endl<<endl;
    MidRecurTraversal(pRoot1);
    cout<<endl<<"       **********后序递归遍历二叉树**********"<<endl<<endl;
    PostRecurTraversal(pRoot1);

    SetConsoleTextColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    cout<<endl<<"******************根据后序和中序建造二叉树********************"<<endl<<endl;
    PostAndMidRecurCreate(pRoot2, MAX_NUM - 1, 0, MAX_NUM);

    SetConsoleTextColor(FOREGROUND_GREEN | FOREGROUND_INTENSITY);
    cout<<endl<<"******************非递归遍历二叉树********************"<<endl<<endl;
    cout<<endl<<"       **********前序非递归遍历二叉树**********"<<endl<<endl;
    PreTraversalOne(pRoot2);
    cout<<endl;
    PreTraversalTwo(pRoot2);
    cout<<endl<<"       **********中序非递归遍历二叉树**********"<<endl<<endl;
    MidTraversal(pRoot2);
    cout<<endl<<"       **********后序非递归遍历二叉树**********"<<endl<<endl;
    PostTraversal(pRoot2);
    return 0;
}
复制代码

输出效果如图所示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值