二叉树的创建(先序创建的)及先序遍历 中序遍历 后序遍历的递归和非递归实现

1. 首先是关于二树结点的设计

typedefstruct TreeNode *PtrToNode;
typedef PtrToNode BinTree;
struct TreeNode
{
    char data;//结点数据,假设是字符
    BinTree left; // 指向左子树
    BinTree right; // 指向右子树
};

2.  其次是二叉树创建的模拟

根据先序次序输入二叉树的结点,从而创建一个二叉树(‘-’字符表示树空,当然也可以是其他字符,比如空格);

例如一棵树结构如下,其输入次序为:abd--fe---cg-h--i--


二叉树根据键盘输入字符的创建模拟函数

BinTree binTreeCreate()
{
    BinTree t;
    char temp;
    scanf("%c", &temp);
    if ('-' == temp)
        t = NULL;
    else
    {
        t = (BinTree)malloc(sizeof(struct TreeNode));
        t->data = temp;
        t->left = binTreeCreate(t->left);
        t->right = binTreeCreate(t->right);
    }
    return t;
}

3. 递归实现的三种遍历(先序 中序 后序)

3.1 先序遍历二叉树的操作定义为:

若二叉树为空,则空操作;否则:

(1) 访问根结点

(2) 先序遍历左子树

(3) 先序遍历右子树

void binTreePreOrderTraversal(BinTree T)
{
    if(T)
    {
        printf("%c ", T->data);
        binTreePreOrderTraversal(T->left);
        binTreePreOrderTraversal(T->right);
    }
}

3.2 中序遍历二叉树的操作定义为:

若二叉树为空,则空操作;否则:

(1) 中序遍历左子树

(2) 访问根结点

(3) 中序遍历右子树

void binTreeInOrderTraversal(BinTree T)
{
    if(T)
    {
        binTreeInOrderTraversal(T->left);
        printf("%c ", T->data);
        binTreeInOrderTraversal(T->right);
    }
}

3.3 后序遍历二叉树的操作定义为:

若二叉树为空,则空操作;否则:

(1) 中序遍历左子树

(2) 中序遍历右子树

(3) 访问根结点

void binTreePostOrderTraversal(BinTree T)
{
    if(T)
    {
        binTreePostOrderTraversal(T->left);
        binTreePostOrderTraversal(T->right);
        printf("%c ", T->data);
    }
}

4. 递归实现的三种遍历(先序 中序 后序)

思路是这样的:

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

下图在从入口到出口的曲线上用三种符号分别标记出了先序、中序和后序访问各结点的时刻。


二叉树的非递归遍历算法实现的基本思路:使用堆栈,依据各结点的访问时序实现即可

4.1 先序遍历非递归思路:

遇到一个结点(第一次遇到),访问它,再把它压栈,并去遍历它的左子树

当左子树遍历结束后,从栈顶弹出这个结点;

然后按其右指针再去先序遍历该结点的右子树。

void binTreePreOrderTraversal(BinTree T)
{
    //创建并初始化堆栈S
    Stack s = CreateStack(MAXSIZE);
    while (T || !IsEmpty(s)) // 循环结点的条件是T空且栈空
    {
        while (T) 
        {
            printf("%c ", T->data);
            Push(s, T);
            T = T->left;
        }
        if (!IsEmpty(s))
        {
            T = Pop(s);
            T = T->right;
        }
    }
}

4.2 中序遍历非递归思路:

遇到一个结点,就把它压栈,并去遍历它的左子树

当左子树遍历结束后,从栈顶弹出这个结点(第二次遇到该结点)并访问它

然后按其右指针再去中序遍历该结点的右子树。

void binTreeInOrderTraversal(BinTree T)
{
    // 创建并初始化堆栈S
    Stack s = CreateStack(MAXSIZE);
    
    while (T || !IsEmpty(s))
    {
        while (T)
        {
            Push(s, T);
            T = T->left;
        }
        if (!IsEmpty(s))
        {
            T = Pop(s);
            printf("%c ", T->data);
            T = T->right;
        }
    }
    
}

4.3 后序遍历非递归思路:

遇到一个结点,就把它压栈(第一次遇到该结点),并去遍历它的左子树

当左子树遍历结束后,从栈顶取出这个结点的值 (第二次遇到该结点),并不进行弹栈处理

然后按其右指针再去后序遍历该结点的右子树;

当其右子树遍历结点后,从栈顶取出该值访问并弹栈;


由时序图可以看出每个结点都可以看作第三次才访问的,即其左右子树都已经进行过遍历,而无论其左右子树有无;

那么在树结点中增加一个flag字段记录结点访问的时序(第几次遇到该结点),很明显后序是第三次,那么可以这么设计:

首先树中每个结点的flag字段默认值为0,将结点首次压栈时,将其flag字段值+1(表明即将遍历其左子树)

依次遍历左子树,当左子树遍历结束后,退出小循环,对栈顶元素进行处理;

若栈顶元素的flag字段值为1,表明其左子树已经遍历完,然后按其右指针再去后序遍历该结点的右子树,flag字段值再+1(表明即将遍历其右子树),此时栈顶元素,并不出栈;

若栈顶元素的flag字段值为2,表明其右子树已经遍历完,那么访问该结点并将其出栈,再对栈中其它元素进行处理。


这里我偷懒就在原结构体上进行了添加字段

struct TreeNode
{
    char data;//结点数据
    BinTree left; // 指向左子树
    BinTree right; // 指向右子树
    int flag; //访问标志,方便后序非递归遍历
};

代码如下:

void binTreePostOrderTraversal(BinTree T)
{
    //创建并初始化堆栈S
    Stack s = CreateStack(MAXSIZE);
    while (T || !IsEmpty(s))
    {
        while (T && T->flag==0)
        {
            T->flag++;//该结点第一次访问,将其入栈
            Push(s, T);
            T = T->left;
        }
        if (!IsEmpty(s))
        {
            T = Top(s);
            if (T->flag ==2)//后序遍历,每个结点基本上可以看做第三次遇到才访问
            {
                T = Pop(s); 
                printf("%c ", T->data);
                T = Top(s);
            }
            else
            {
                T->flag++;//该结点第二次遇到,此时结点在栈中,但不出栈
                T = T->right; // 处理其右子树
            }
        }
    }
}



  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 先序遍历: 1. 访问根节点 2. 先序遍历左子树 3. 先序遍历右子树 中序遍历: 1. 中序遍历左子树 2. 访问根节点 3. 中序遍历右子树 后序遍历: 1. 后序遍历左子树 2. 后序遍历右子树 3. 访问根节点 递归实现: 对于每个节点,先递归遍历左子树,再递归遍历右子树,最后访问该节点。 先序遍历递归实现: void preOrder(TreeNode* root) { if (root == nullptr) return; cout << root->val << " "; //访问根节点 preOrder(root->left); //先序遍历左子树 preOrder(root->right); //先序遍历右子树 } 中序遍历递归实现: void inOrder(TreeNode* root) { if (root == nullptr) return; inOrder(root->left); //中序遍历左子树 cout << root->val << " "; //访问根节点 inOrder(root->right); //中序遍历右子树 } 后序遍历递归实现: void postOrder(TreeNode* root) { if (root == nullptr) return; postOrder(root->left); //后序遍历左子树 postOrder(root->right); //后序遍历右子树 cout << root->val << " "; //访问根节点 } ### 回答2: 二叉树是一种非常常用的数据结构,在计算机领域的应用非常广泛。在遍历二叉树时,常用的三种方式为先序遍历中序遍历以及后序遍历。其中,先序遍历可以理解为先遍历根节点,再遍历左子树,最后遍历右子树;中序遍历可以理解为先遍历左子树,再遍历根节点,最后遍历右子树;后序遍历可以理解为先遍历左子树,再遍历右子树,最后遍历根节点。要实现这三种遍历方法,可以采用递归算法。 递归是指在算法或者函数中调用自身的一种方法。在二叉树遍历中,递归实现非常简单,只需要在遍历时将左子树和右子树分别传入递归函数即可。具体来说,先序遍历时,可以先输出根节点的值,然后递归遍历左子树和右子树;中序遍历时,先递归遍历左子树,然后输出根节点的值,最后递归遍历右子树;后序遍历时,先递归遍历左子树和右子树,最后输出根节点的值。 下面给出Java代码的示例,代码实现二叉树先序遍历中序遍历后序遍历: ``` class Node { int val; Node left; Node right; Node(int val) { this.val = val; left = right = null; } } class BinaryTree { Node root; // 先序遍历 void preOrderTraversal(Node node) { if (node == null) return; System.out.print(node.val + " "); preOrderTraversal(node.left); preOrderTraversal(node.right); } // 中序遍历 void inOrderTraversal(Node node) { if (node == null) return; inOrderTraversal(node.left); System.out.print(node.val + " "); inOrderTraversal(node.right); } // 后序遍历 void postOrderTraversal(Node node) { if (node == null) return; postOrderTraversal(node.left); postOrderTraversal(node.right); System.out.print(node.val + " "); } public static void main(String[] args) { BinaryTree tree = new BinaryTree(); tree.root = new Node(1); tree.root.left = new Node(2); tree.root.right = new Node(3); tree.root.left.left = new Node(4); tree.root.left.right = new Node(5); System.out.print("先序遍历结果:"); tree.preOrderTraversal(tree.root); System.out.println(); System.out.print("中序遍历结果:"); tree.inOrderTraversal(tree.root); System.out.println(); System.out.print("后序遍历结果:"); tree.postOrderTraversal(tree.root); System.out.println(); } } ``` 在上面的代码中,Node表示二叉树的节点,BinaryTree表示二叉树本身。在main方法中,我们构造了一个简单的二叉树,并对其进行先序遍历中序遍历后序遍历,输出了遍历结果。 综上所述,递归算法是实现二叉树遍历非常简单而高效的方法,可以在遍历时将左右子树分别传入递归函数中,实现遍历。 ### 回答3: 二叉树是数据结构中比较经典的一种类型,其用途十分广泛,比如可以用来实现搜索、排序和表达式求值等。二叉树是由节点构成的树形结构,每个节点最多有两个孩子节点,分别为左孩子和右孩子,因此也被称为二叉查找树。 在二叉树的遍历中,常用的算法有先序遍历中序遍历后序遍历先序遍历指按照“根-左-右”的顺序访问每个节点;中序遍历指按照“左-根-右”的顺序访问每个节点;后序遍历指按照“左-右-根”的顺序访问每个节点。递归算法是实现二叉树遍历的一种常见方法,下面将分别介绍三种遍历方式的递归算法实现先序遍历: 先将根节点输出,然后递归遍历左子树和右子树,直到整棵树遍历完毕。 C++代码实现: void preorder(TreeNode* root) { if(root == nullptr) return; cout << root->val << " "; preorder(root->left); preorder(root->right); } 中序遍历: 先递归遍历左子树,输出根节点,再递归遍历右子树。 C++代码实现: void inorder(TreeNode* root) { if(root == nullptr) return; inorder(root->left); cout << root->val << " "; inorder(root->right); } 后序遍历: 先递归遍历左子树和右子树,最后输出根节点。 C++代码实现: void postorder(TreeNode* root) { if(root == nullptr) return; postorder(root->left); postorder(root->right); cout << root->val << " "; } 以上就是用递归算法实现二叉树遍历的方式,相比较而言,递归算法虽然易于理解和实现,但对于大规模的二叉树,其效率并不高,因此在实际应用中需要选择合适的遍历算法来保证效率的同时满足需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值