树的遍历及相关递归函数

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stack>
#include <iostream>

typedef struct tag_Tree         //二叉树
{
    char data;
    struct tag_Tree* lchild;
    struct tag_Tree* rchild;
}Tree;
/*
函数功能: 访问树的节点
*/
void Visit(Tree* t)
{
    printf("元素为:%c\n", t->data);
}
/*
函数功能:先序遍历一棵树;
注意:任何树的遍历方式,遍历一棵树的路径相同,只是访问的时间不同
*/
void PreOrder(Tree* root)
{
    if (root == NULL)
    {
        return;
    }
    Visit(root);//先序
    PreOrder(root->lchild);
    PreOrder(root->rchild);
}
void InOrder(Tree* root)
{
    if (root == NULL)
    {
        return;
    }
    InOrder(root->lchild);
    Visit(root);//中序
    InOrder(root->rchild);
}
void PostOrder(Tree* root)
{
    if (root == NULL)
    {
        return;
    }
    PostOrder(root->lchild);    
    PostOrder(root->rchild);
    Visit(root);//后序
}
/*
函数功能:计算树的叶子节点数
*/
void CountOfLeaf(Tree* root ,int * count)
{
    if (root == NULL)
    {
        return;
    }
    if ((root->lchild == NULL) && (root->rchild == NULL))
    {
        ++*count;//先序
        Visit(root);
    }
    CountOfLeaf(root->lchild,count);
    CountOfLeaf(root->rchild,count);
}

/*
函数功能:计算树的深度,根节点深度为0
*/
int DepthOfTree(Tree* root)
{
    int leftDepth = 0;
    int rightDepth = 0;
    if (root == NULL)
    {
        return 0;
    }
    leftDepth = DepthOfTree(root->lchild);
    rightDepth = DepthOfTree(root->rchild);
    return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
}
/*
函数功能:计算树的叶子节点数
*/
int CountOfTree(Tree* root)
{
    int lchild = 0;
    int rchild = 0;
    if (root == NULL)
    {
        return 0;
    }
    if ((root->lchild == NULL) && (root->rchild == NULL))
    {
        return 1;
    }
    lchild = CountOfTree(root->lchild);
    rchild = CountOfTree(root->rchild);
    return lchild + rchild;
}
/*
函数功能:树的拷贝
*/
Tree* CopyTree(Tree* root)
{
    Tree* newT = NULL;
    if (root == NULL)   {
        return NULL;
    }
    //先序拷贝
    newT = (Tree*)malloc(sizeof(Tree));
    if (newT == NULL)   {
        return NULL;
    }
    newT->data = root->data;

    newT->lchild = CopyTree(root->lchild);
    newT->rchild = CopyTree(root->rchild);
    return newT;
}
using namespace std;
//到达树的最左边的节点
Tree* GoLeft(Tree* lchild, stack<Tree*>& s)
{
    while (lchild->lchild != NULL)
    {
        s.push(lchild);
        lchild = lchild->lchild;
    }
    return lchild;
}
/*前序遍历:非递归*/
void PreOrder2(Tree* root)
{
    stack<Tree*> s;
    Tree* p = root;
    while (!s.empty() || p)//栈不为空或者p不为空
    {
        if (p)
        {
            Visit(p);//访问该节点
            s.push(p);//节点入栈
            p = p->lchild;//左子树
        }
        else//没有左子树
        {
            p = s.top();//弹出父节点
            s.pop();
            p = p->rchild;//右子树
        }
    }
}
/*函数功能:中序遍历树的非递归*/
void InOrder2(Tree* root)
{
    /*
    步骤1:
    如果该节点有左子树,该节点入栈;
    如果该节点没有左子树,访问该节点;
    步骤2:
    如果该节点有右子树,该节点入栈,接步骤一;
    如果该节点没有右子树,访问该节点,退到栈顶,;
    */
    Tree* t = NULL;
    stack<Tree*> s;
    if (root == NULL)
    {
        return;
    }
    t = GoLeft(root, s);//最左的节点
    while (t != NULL)
    {
        Visit(t);
        if (t->rchild != NULL)//节点有右子树
        {
            t = GoLeft(t->rchild, s);
        }
        else if (!s.empty())//没有右子树,且栈不为空
        {
            t = s.top();//根节点
            s.pop(); 
        }
        else
        {
            t = NULL;//访问完毕
        }
    }
}

void InOrder3(Tree* root)
{
    stack<Tree*> s;
    Tree* p = root;
    while (p != NULL || !s.empty())
    {
        while (p != NULL)
        {
            s.push(p);
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            Visit(p);
            s.pop();
            p = p->rchild;
        }
    }
}
/*后序遍历非递归
要保证根结点在左孩子和右孩子访问之后才能访问,
因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子
,则可以直接访问它;或者P存在左孩子或者右孩子,
但是其左孩子和右孩子都已被访问过了,
则同样可以直接访问该结点。若非上述两种情况,
则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,
左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
*/
void PostOrder2(Tree* root)
{
    if (root == NULL)
    {
        return;
    }
    stack<Tree*> s;
    Tree* cur;
    Tree* pre = NULL;
    s.push(root);
    while (!s.empty())
    {
        cur = s.top();
        if ((cur->lchild == NULL && cur->rchild == NULL)
            || (pre != NULL && (pre == cur->lchild || pre == cur->rchild)))
        {
            Visit(cur);//如果当前结点没有孩子结点或者孩子节点都已被访问过 
            s.pop();
            pre = cur;
        }
        else
        {
            if (cur->rchild != NULL)
            {
                s.push(cur->rchild);
            }
            if (cur->lchild != NULL)
            {
                s.push(cur->lchild);
            }
        }
    }
}
struct BTNode
{
    Tree* btnode;
    bool isFirst;
};
/*
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,
直到搜索到没有左孩子的结点,此时该结点出现在栈顶,
但是此时不能将其出栈并访问,因其右孩子还为被访问。
所以接下来按照相同的规则对其右子树进行相同的处理,
当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。
这样就保证了正确的访问顺序。可以看出,在这个过程中,
每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。
因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
*/
void PostOrder3(Tree* root)
{
    stack<BTNode*> s;
    Tree* p = root;
    BTNode* temp;
    while (p != NULL || !s.empty())
    {
        while (p != NULL)
        {
            BTNode* btn = new BTNode;
            btn->btnode = p;
            btn->isFirst = true;
            s.push(btn);
            p = p->lchild;
        }
        if (!s.empty())
        {
            temp = s.top();
            s.pop();
            if (temp->isFirst == true)
            {
                temp->isFirst = false;
                s.push(temp);
                p = temp->btnode->rchild;
            }
            else
            {
                Visit(temp->btnode);
                delete temp;
                temp = NULL;
                p = NULL;
            }
        }
    }
}
/*函数功能:先序创建一棵树*/
Tree* CreateTree()
{
    Tree* t = NULL;
    char ch;
    scanf("%c", &ch);
    if (ch == '#'){
        return NULL;
    }
    else{
        t = (Tree*)malloc(sizeof(Tree));
        memset(t, 0, sizeof(Tree));
        if (t == NULL){
            return NULL;
        }
        t->data = ch;
        t->lchild = CreateTree();
        t->rchild = CreateTree();
    }
    return t;
}

int main()
{
    Tree* myTree = NULL;
    myTree = CreateTree();
    if (myTree != NULL)
    {
        PostOrder(myTree);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值