C#--二叉树的遍历(递归和非递归)

二叉树的遍历

包含四种遍历方式:

前序遍历

中序遍历

后序遍历

层次遍历

一.前序遍历

   前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。

  1.递归实现

// 前序遍历:首先访问根结点,然后遍历其左子树,最后遍历其右子树。
    private void PreOrder(TreeNode<T> node)
    {
        if (node == null)
        {
            return;
        }
        //打印节点数据
        Console.WriteLine(node.Data);
        PreOrder(node.LeftChild);
        PreOrder(node.RightChild);
    }

2.非递归实现

        实现思路:根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问完左子树时,再访问它的右子树。因此其处理过程如下:

     对于任一结点P:

     1)访问结点P,并将结点P入栈;

     2)若结点P的右孩子不为空,把右孩子结点入栈;

     3)若结点P的左孩子不为空,则将左孩子结点置为当前的结点P;

     4)当遍历完左子树,Pop出右孩子结点,继续上面的遍历;

     4)直到P为null并且栈为空,则遍历结束。

 

 

// 对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。
    // 前序遍历
    private void PreOrder1(TreeNode<T> node)
    {
        Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
        TreeNode<T> curNode = node;
        s.Push(node);
        while (s.Count > 0)
        {
            Console.WriteLine(curNode.Data);
            if (curNode.RightChild != null)
            {
                s.Push(curNode.RightChild);
            }
            if (curNode.LeftChild != null)
            {
                curNode = curNode.LeftChild;
            }
            else
            {
                //左子树访问完了,访问右子树
                curNode = s.Pop();
            }
        }
    }

二.中序遍历

    中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。

    1.递归实现

// 中序遍历:首先遍历其左子树,然后访问根结点,最后遍历其右子树。
    private void InOrder(TreeNode<T> node)
    {
        if (node == null)
        {
            return;
        }
        InOrder(node.LeftChild);
        //打印节点数据
        Console.WriteLine(node.Data);
        InOrder(node.RightChild);
    }

2.非递归实现

       实现思路:根据中序遍历的顺序,对于任一结点,优先遍历其左孩子,而左孩子结点不为空,然后继续遍历其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:

   对于任一结点P,

  1)访问结点P,并将结点P入栈;

  2)优先遍历其左孩子,而左孩子结点不为空,然后继续遍历其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,出栈左孩子节点,然后遍历右孩子节点,继续出栈,直至出栈根节点,继续遍历右子树;

  3)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将栈顶结点的右孩子置为当前的P;

// 对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。
    // 中序遍历
    private void InOrder1(TreeNode<T> node)
    {
        Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
        TreeNode<T> curNode = node;
        while (curNode != null || s.Count > 0)
        {
            while (curNode != null)
            {
                s.Push(curNode);
                curNode = curNode.LeftChild;
            }
            if (s.Count > 0)
            {
                curNode = s.Pop();
                Console.WriteLine(curNode.Data);
                curNode = curNode.RightChild;
            }
        }
    }

 三.后序遍历

      后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。

      1.递归实现

// 后序遍历:首先遍历其左子树,然后遍历其右子树,最后访问根结点。
    private void PostOrder(TreeNode<T> node)
    {
        if (node == null)
        {
            return;
        }
        PostOrder(node.LeftChild);
        PostOrder(node.RightChild);
        //打印节点数据
        Console.WriteLine(node.Data);
    }

2.非递归实现

        后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。

      实现思路:

1)先把根节点入栈

2)取得栈顶元素,如果当前结点没有孩子节点或者孩子节点都已经被访问,那么出栈,访问其数据

3)否则,如果右孩子节点不为空,入栈。如果左孩子不为空,入栈。要保证入栈顺序,先右孩子再左孩子节点。

4)只要栈中还有元素,就循环执行2)3)

注意:要保证根结点在左孩子和右孩子访问之后才能访问

    // 后序遍历
    private void PostOrder1(TreeNode<T> node)
    {
        Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
        TreeNode<T> curNode = null;
        TreeNode<T> preNode = null;
        s.Push(node);
        while (s.Count > 0)
        {
            curNode = s.Peek();
            if ((curNode.LeftChild == null && curNode.RightChild == null) ||
                (preNode != null && (preNode == curNode.LeftChild || preNode == curNode.RightChild)))
            {
                //如果当前结点没有孩子结点或者孩子节点都已被访问过   
                Console.WriteLine(curNode.Data);
                s.Pop();
                preNode = curNode;
            }
            else
            {
                if (curNode.RightChild != null)
                {
                    s.Push(curNode.RightChild);
                }
                if (curNode.LeftChild != null)
                {
                    s.Push(curNode.LeftChild);
                }
            }
        }
    }

四、层次遍历

从树的第一层开始,从上到下逐层遍历,在同一层中,从左到右对结点逐个访问输出,采用队列的方式进行层次遍历

// 层次遍历
        private void HierarchyOrder(TreeNode<T> node)
        {
            Queue<TreeNode<T>> s = new Queue<TreeNode<T>>();
            s.Enqueue(node);
            while(s.Count > 0)
            {
                TreeNode<T> curNode = s.Dequeue();
                Console.WriteLine(curNode.Data);
                if(curNode.LeftChild != null)
                {
                    s.Enqueue(curNode.LeftChild);
                }
                if(curNode.RightChild != null)
                {
                    s.Enqueue(curNode.RightChild);
                }
            }
        }

 

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来回答你的问题。以下是使用C语言解决你提出的问题的完整代码: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树结点 typedef struct TreeNode { char data; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 建立二叉链表 TreeNode* createBinaryTree() { char ch; scanf("%c", &ch); if (ch == '#') { // 如果输入的是 #,则返回 NULL return NULL; } TreeNode *node = (TreeNode*)malloc(sizeof(TreeNode)); node->data = ch; node->left = createBinaryTree(); // 递归建立左子树 node->right = createBinaryTree(); // 递归建立右子树 return node; } // 中序遍历二叉树递归算法 void inorderTraversal(TreeNode *root) { if (root == NULL) { return; } inorderTraversal(root->left); printf("%c ", root->data); inorderTraversal(root->right); } // 中序遍历二叉树非递归算法 void inorderTraversalWithoutRecursion(TreeNode *root) { TreeNode *stack[100]; int top = -1; TreeNode *p = root; while (p != NULL || top != -1) { if (p != NULL) { stack[++top] = p; p = p->left; } else { p = stack[top--]; printf("%c ", p->data); p = p->right; } } } // 求二叉树的高度 int getHeight(TreeNode *root) { if (root == NULL) { return 0; } int leftHeight = getHeight(root->left); int rightHeight = getHeight(root->right); return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; } int main() { printf("请输入二叉树的字符序列(用 # 表示空结点):\n"); TreeNode *root = createBinaryTree(); printf("中序遍历二叉树递归算法):\n"); inorderTraversal(root); printf("\n"); printf("中序遍历二叉树非递归算法):\n"); inorderTraversalWithoutRecursion(root); printf("\n"); printf("二叉树的高度为:%d\n", getHeight(root)); return 0; } ``` 输入例子: ``` AB#D##C## ``` 输出例子: ``` 请输入二叉树的字符序列(用 # 表示空结点): 中序遍历二叉树递归算法): A B D C 中序遍历二叉树非递归算法): A B D C 二叉树的高度为:3 ``` 注意:在输入字符序列时,每个字符之间需要用空格隔开。例如,上面的输入例子应该输入为 `A B # D # # C # #`,而不是 `AB#D##C##`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值