用递归算法先序中序后序遍历二叉树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用递归算法先序中序后序遍历二叉树相关的知识,希望对你有一定的参考价值。

用C编写的,编译能通过的,不要伪代码,给高分
最好再给非递归的c.

1、先序

void PreOrderTraversal(BinTree BT)

    if( BT ) 

   

        printf(“%d\\n”, BT->Data);        //对节点做些访问比如打印         

        PreOrderTraversal(BT->Left);     //访问左儿子

        PreOrderTraversal(BT->Right);    //访问右儿子

   

2、中序

void InOrderTraversal(BinTree BT)

    if(BT)

   

        InOrderTraversal(BT->Left);

        printf("%d\\n", BT->Data);

        InOrderTraversal(BT->Right);

   

3、后序

void PostOrderTraversal(BinTree BT)

    if (BT)

   

        PostOrderTraversal(BT->Left);

        PostOrderTraversal(BT->Right);

        printf("%d\\n", BT->Data);

   

扩展资料:

注意事项

1、前序遍历 

从整棵二叉树的根结点开始,对于任意结点VV,访问结点VV并将结点VV入栈,并判断结点VV的左子结点LL是否为空。若LL不为空,则将LL置为当前结点VV;若LL为空,则取出栈顶结点,并将栈顶结点的右子结点置为当前结点VV。

2、中序遍历 

从整棵二叉树的根结点开始,对于任一结点VV,判断其左子结点LL是否为空。若LL不为空,则将VV入栈并将L置为当前结点VV;若LL为空,则取出栈顶结点并访问该栈顶结点,然后将其右子结点置为当前结点VV。重复上述操作,直到当前结点V为空结点且栈为空,遍历结束。

3、后序遍历 

将整棵二叉树的根结点入栈,取栈顶结点VV,若VV不存在左子结点和右子结点,或VV存在左子结点或右子结点,但其左子结点和右子结点都被访问过了,则访问结点VV,并将VV从栈中弹出。若非上述两种情况,则将VV的右子结点和左子结点依次入栈。重复上述操作,直到栈为空,遍历结束。

参考技术A #include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef char TElemType;
typedef struct Btn
TElemType data;
struct Btn *lchild , *rchild;
BTN ,*BT;
int CreateBT(BT &T)
//按前序遍历规则创建二叉树,请输入结点
//(不存在的结点用*代替),如"AB*DG***CEM**N**F*X**"
char ch;
getchar();
printf("\n请输入二叉树的元素\n");
scanf("%c",&ch);
if(ch == '*')T = NULL;
else
if(!(T = (BTN *)malloc(sizeof(BTN)))) exit(OVERFLOW);
T->data = ch;
CreateBT(T->lchild);
CreateBT(T->rchild);

return OK;
//创建二叉树
int PreOrderT(BT T )
//前序遍历二叉树 T:打印每个结点的数据域一次且仅一次
if (T != NULL)
printf("%c \n", T -> data);
PreOrderT( T -> lchild ) ;
PreOrderT( T -> rchild ) ;

return OK;
//先序遍历二叉树
int InOrderT(BT T)
//后序遍历二叉树 T:打印每个结点的数据域一次且仅一次
if (T != NULL)
InOrderT( T -> lchild ) ;
printf("%c \n", T -> data);
InOrderT( T -> rchild ) ;

return OK;
//后序遍历二叉树 T
int PostOrderT(BT T)
//后序遍历二叉树 T:打印每个结点的数据域一次且仅一次
if (T != NULL)
PostOrderT( T -> lchild ) ;
PostOrderT( T -> rchild ) ;
printf("%c \n", T -> data);

return OK;
//后序遍历二叉树 T
BT LocateElem(BT T , TElemType e)
//编写算法在二叉树T(二叉链表存储结构)中查找数据元素e。
//查找成功返回结点地址;否则返回NULL
BT s;
if (T->data == e || T == NULL ) return (T);
s = LocateElem ( T -> lchild, e ) ;
if ( s != NULL ) return (s);
else return ( LocateElem ( T -> rchild , e ) ) ;
//中查找数据元素e
int BTnum(BT T)
// 编写算法统计二叉树T(二叉链表存储结构)的结点总数
int i=0;
if (T != NULL)
InOrderT( T -> lchild ) ;
i++;
InOrderT( T -> rchild ) ;

return i;

int BTdepth(BT T)
//编写算法求二叉树T(二叉链表存储结构)的深度。
int rd,ld;
if(!T) return 0;
else ld=BTdepth(T->lchild);
rd=BTdepth(T->rchild);
if(ld>rd) return rd+1;
else return ld+1;


/*int LevelElem(BT T,TElemType e)
//求e在T中的层次。如果不存在,返回值为0;否则,返回值为层次。
int rd,ld;
if(!T) return 0;
else
if(e!=T->data)
ld=BTdepth(T->lchild);
rd=BTdepth(T->rchild);
if(ld>rd)
return rd+1;
else return ld+1;

*/
int main()
BT T;
TElemType e;
int /*Te,*/j;
while(j)
printf("\n请输入你要的功能\n");
printf("-----华丽的分割线------\n");
printf("1:按前序遍历规则创建二叉树\n");
printf("2:前序遍历二叉树 T\n");
printf("3:中序遍历二叉树 T\n");
printf("4:后序遍历二叉树 T\n");
printf("5:查找数据元素e\n");
printf("6:统计二叉树T的结点总数\n");
printf("7:编写算法求二叉树T的深度\n");
printf("0:退出程序\n");
// printf("8:求e在T中的层次\n");
printf("-----华丽的分割线------\n");
scanf("%d",&j);
switch(j)
case 1:CreateBT(T);break;
case 2:PreOrderT(T);break;
case 3:InOrderT(T);break;
case 4:PostOrderT(T);break;
case 5:
printf("\n请输入想要查找的元素\n");
scanf("%c",&e);
LocateElem(T,e);break;
case 6: BTnum(T);
case 7:BTdepth(T);break;
/* case 8:
printf("\n请输入元素\n");
scanf("%c",&e);
Te=LevelElem(T,e);
printf("\n%c的层数为%d\n",e,Te);
break;*/
case 0:exit(1);


return 0;

给分本回答被提问者采纳
参考技术B 我有C++的不知道,能不能帮到你?

用递归和非递归方式实现二叉树的先序中序后序遍历

很久没写博客了,也很久没有静下心来学习技术,具体原因不再多纠结。

最近完成零丁任务之余每天刷一刷LeetCode,看看书(比如这篇记录的是左程云大佬的《程序员代码面试指南》中的内容)

温习和学习一些算法以及相关知识,巩固一下基础。

算法的程序代码大多不是自己初次AC所写,因为在翻阅书籍和欣赏discuss区大佬的代码与100%击败率的代码时,

经常能发现更为简洁和漂亮的写法,有时候甚至能发现某些“惊为天人”的操作(基操,勿6)。

内容可能和以前写的有所重复,大同小异,换了java的实现,然后有所拓展。

好吧,渣渣的逼逼叨叨到此结束。

 

树结构定义

    public class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int x) {
            this.val = x;
        }
    }

 

先序、中序、后序指的是根节点,先序:根左右;中序:左根右;后序:左右根。

递归方式如下,之间的差别就是调整了输出语句的位置。

技术分享图片
    public void preOrderRecur(TreeNode root) {
        if (root == null)
            return;
        System.out.println(root.val);
        preOrderRecur(root.left);
        preOrderRecur(root.right);
    }

    public void inOrderRecur(TreeNode root) {
        if (root == null)
            return;
        inOrderRecur(root.left);
        System.out.println(root.val);
        inOrderRecur(root.right);
    }

    public void posOrderRecur(TreeNode root) {
        if (root == null)
            return;
        posOrderRecur(root.left);
        posOrderRecur(root.right);
        System.out.println(root.val);
    }
View Code

 

用递归方法解决的问题都能用非递归的方法实现。因为递归方法利用了函数栈来保存信息,如果用自己申请的数据结构代替函数栈,也能实现相同功能。

非递归的先序遍历:

1、申请栈,头节点入栈;

2、弹出栈顶并打印,右孩子入栈(不null),左孩子入栈(不null);

3、不断重复步骤2,直到栈空。

    public void preOrderUnRecur(TreeNode root) {
        if (root == null)
            return;
        Stack<TreeNode> s = new Stack<TreeNode>();
        s.push(root);
        while (!s.isEmpty()) {
            root = s.pop();
            System.out.println(root.val);
            if (root.right != null)
                s.push(root.right);
            if (root.left != null)
                s.push(root.left);
        }
    }

 

非递归的中序遍历:

1、申请栈,令cur=root;

2、cur入栈,不断令cur=cur.left并入栈;

3、cur==null时,从栈中弹出一个节点node并打印,令cur=node.right,重复步骤2;

4、重复2、3直到栈空且cur空。

    public void inOrderUnRecur(TreeNode root) {
        if (root == null)
            return;
        Stack<TreeNode> s = new Stack<TreeNode>();
        while (!s.isEmpty() || root != null) {
            if (root != null) {
                s.push(root);
                root = root.left;
            } else {
                root = s.pop();
                System.out.println(root.val);
                root = root.right;
            }
        }
    }

 

非递归的后序遍历:

首先是两个栈的实现方式,比较好理解:

1、申请栈s1,s2,头节点 入s1;

2、s1中弹出节点记为cur,cur压入s2,cur左右孩子依次压入s1;

3、重复2直到s1为空;

4、从s2中不断出栈并打印。

解释:每颗子树的头节点都最先从s1中弹出,然后把该节点的孩子按照先左再右的顺序压入s1,

那么从s1中弹出的顺序就是先右再左,总的顺序就是中右左,则从s2中弹出的顺序是左右中(逆s1)。

    // two stacks
    public void posOrderUnRecur1(TreeNode root) {
        if (root == null)
            return;
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        s1.push(root);
        while (!s1.isEmpty()) {
            // 每颗子树的头节点都最先从s1中弹出
            root = s1.pop();
            s2.push(root);
            // 先左后右压入,总的出栈顺序为中右左,则s2出栈顺序为左右中
            if (root.left != null)
                s1.push(root.left);
            if (root.right != null)
                s1.push(root.right);
        }
        while (!s2.isEmpty())
            System.out.println(s2.pop().val);
    }

 

然后是一个栈的实现方式:

1、申请栈,头节点入栈,设置变量h和c,h代表最近一次弹出并打印的节点,c代表栈顶节点,初试时h为头节点,c为null;

2、令c=stack.peek(); //即令c等于栈顶节点,但栈顶不弹出,分三种情况:

Ⅰ  如果 c.left != null,且 h != c.left,且 h!=c.right,则c的左孩子入栈。

解释:h代表最近一次弹出并打印的节点,如果 h==c.left 或者 h==c.right,说明c的左子树和右子树已经打印完毕,

不应该再把c的左孩子入栈。否则,说明c的左子树还没有处理过,则c的左孩子入栈。

Ⅱ  如果条件Ⅰ不成立,且 c.right != null,且 h != c.right,则c的右孩子入栈。

Ⅲ  如果Ⅰ和Ⅱ都不成立,说明c的左子树和右子树都打印完毕,则从栈中弹出c并打印,令h=c。

3、重复步骤2直到栈为空。

    // h代表最近一次弹出并打印的节点,c代表stack的栈顶节点
    // 初试时h为头节点,c为null
    public void posOrderUnRecur2(TreeNode h) {
        if (h == null)
            return;
        Stack<TreeNode> s = new Stack<TreeNode>();
        s.push(h);
        TreeNode c = null;
        while (!s.isEmpty()) {
            c = s.peek();
            if (c.left != null && h != c.left && h != c.right)
                s.push(c.left);
            else if (c.right != null && h != c.right)
                s.push(c.right);
            else {
                System.out.println(s.pop().val);
                h = c;
            }
        }
    }

 

以上是关于用递归算法先序中序后序遍历二叉树的主要内容,如果未能解决你的问题,请参考以下文章

二叉树问题:递归方式实现二叉树先序中序后序遍历

算法练习28:非递归方式遍历二叉树的先序中序后序

二叉树的非递归遍历(先序中序后序和层序遍历)

二叉树遍历(先序中序后序)

详解二叉树的遍历问题(前序后序中序层序遍历的递归算法及非递归算法及其详细图示)

二叉树遍历的递归实现(先序中序后序和层次遍历)