二叉树的三种遍历(递归,栈)

雨点打透心脏的1/2处 2023-07-08 12:24 60阅读 0赞

二叉树的先序遍历

数据访问顺序:根结点———->左孩子———->又孩子

使用递归

使用了分治法:将一个大树向下一层层的分为多个小子树

  1. /**
  2. * 先序遍历,使用递归,输出树中所有结点
  3. * @param rootNode 根结点
  4. */
  5. public static void preOrder(TreeNode rootNode) {
  6. TreeNode moveNode = rootNode;
  7. if(moveNode != null) {
  8. System.out.print(moveNode.getData()+" ");
  9. preOrder(moveNode.getLeChild());
  10. preOrder(moveNode.getRiChild());
  11. }
  12. }

使用栈

利用栈的特性:对每个小子树的根结点进行存储,使得访问左子树后,右子树的追踪不会丢失
数据在入栈时进行访问

  1. /**
  2. * 使用栈来进行先序遍历
  3. * @param rootNode 根结点
  4. */
  5. public static void stackPreOrder(TreeNode rootNode) {
  6. TreeNode moveNode = rootNode;
  7. //构造长度为10的栈
  8. TreeNode[] stack = new TreeNode[10];
  9. int i = 0;
  10. //栈不为空且还有数据
  11. while(moveNode != null || i != 0) {
  12. while(moveNode != null) {
  13. //遍历左子树入栈
  14. stack[i++] = moveNode;
  15. System.out.print(moveNode.getData()+" ");
  16. moveNode = moveNode.getLeChild();
  17. }
  18. while((moveNode = stack[--i].getRiChild()) == null) {
  19. if(i == 0) {
  20. //当栈空,还没有右子树,遍历结束
  21. return;
  22. }
  23. }
  24. }
  25. }

PS:在这里我使用循环嵌套,可能美观性有点不太好,但易于理解

二叉树的中序遍历

数据访问顺序:左孩子———->根结点———->右孩子

使用递归

大致和先序遍历相同

  1. /**
  2. * 中序遍历,使用递归
  3. * @param rootNode 根结点
  4. */
  5. public static void inOrder(TreeNode rootNode) {
  6. TreeNode moveNode = rootNode;
  7. if(moveNode != null) {
  8. inOrder(moveNode.getLeChild());
  9. System.out.print(moveNode.getData()+" ");
  10. inOrder(moveNode.getRiChild());
  11. }
  12. }

使用栈

数据的输出位置发生变化,即在出栈位置进行访问

  1. /**
  2. * 使用栈完成中序遍历
  3. * @param rootNode 根结点
  4. */
  5. public static void stackInOrder(TreeNode rootNode) {
  6. TreeNode moveNode = rootNode;
  7. TreeNode[] stack = new TreeNode[10];
  8. int i = 0;
  9. //栈不为空,且还有数据
  10. while(moveNode != null || i != 0) {
  11. while(moveNode != null) {
  12. //遍历左子树入栈
  13. stack[i++] = moveNode;
  14. moveNode = moveNode.getLeChild();
  15. }
  16. //循环出栈,找出右子树未空的结点
  17. while((moveNode = stack[--i].getRiChild()) == null) {
  18. //若无右子树,直接输出当前结点值
  19. System.out.print(stack[i].getData()+" ");
  20. if(i == 0) {
  21. //当栈空,还没有右子树,遍历结束
  22. return;
  23. }
  24. }
  25. //输出有右子树的结点值
  26. System.out.print(stack[i].getData()+" ");
  27. }
  28. }

二叉树的后序遍历

数据访问顺序:左孩子———->右孩子———->根结点

使用递归

大致和先序遍历相同

  1. /**
  2. * 后序遍历,使用递归
  3. * @param rootNode 根结点
  4. */
  5. public static void postOrder(TreeNode rootNode) {
  6. TreeNode moveNode = rootNode;
  7. if(moveNode != null) {
  8. postOrder(moveNode.getLeChild());
  9. postOrder(moveNode.getRiChild());
  10. System.out.print(moveNode.getData()+" ");
  11. }
  12. }

使用栈

由于后续遍历的特殊性,若子树根结点有右子树,则需先遍历子树的右子树,再输出子树根结点,此处需要对根结点进行二次访问(第一次得到右子树的入口,第二次访问数据)。若根结点直接出栈,会导致追踪丢失,因此设一个标记对子树根结点进行判断。
判断内容:是否为第一次访问

  1. /**
  2. * 借用栈完成后序遍历
  3. * @param rootNode 根结点
  4. */
  5. public static void stackPostOrder(TreeNode rootNode) {
  6. TreeNode moveNode = rootNode;
  7. //构造长度为10的栈
  8. TreeNode[] stack = new TreeNode[20];
  9. //设置标记数组,和栈同步操作,0为入栈,1为遇到一次
  10. int[] mark = new int[20];
  11. int i = 0;
  12. int j = 0;
  13. //将根归栈
  14. //栈不为空时
  15. while(moveNode != null || i != 0) {
  16. if(moveNode != null) {
  17. stack[i++] = moveNode;
  18. mark[j++] = 0;
  19. moveNode = moveNode.getLeChild();
  20. }else {
  21. //无右子树,直接输出
  22. if(stack[i-1].getRiChild() == null) {
  23. System.out.print(stack[--i].getData()+" ");
  24. j--;
  25. moveNode = null;
  26. }else if(stack[i-1].getRiChild() != null && mark[j-1] != 1) {
  27. //若即将出栈结点有右子树且标记为0时,则不出栈只取值
  28. moveNode = stack[i-1].getRiChild();
  29. mark[i-1] = 1; //修改标记
  30. }else if(stack[i-1].getRiChild() != null && mark[j-1] == 1) {
  31. //在遍历完右子树之后,出栈,直接输出
  32. System.out.println(stack[--i]+" ");
  33. j--;
  34. moveNode = null;
  35. }
  36. }
  37. }
  38. }

PS:此处只使用了一个主循环,之前的遍历也可统一为一个主循环

测试

测试树:
在这里插入图片描述

测试调用:

  1. System.out.print("使用递归的先序遍历:");
  2. preOrder(rootNode);
  3. System.out.print("\r\n"+"使用递归的中序遍历:");
  4. inOrder(rootNode);
  5. System.out.print("\r\n"+"使用递归的后序遍历:");
  6. postOrder(rootNode);
  7. System.out.print("\r\n"+"使用栈的先序遍历:");
  8. stackPreOrder(rootNode);
  9. System.out.print("\r\n"+"使用栈的中序遍历:");
  10. stackInOrder(rootNode);
  11. System.out.print("\r\n"+"使用栈的后序遍历:");
  12. postOrder(rootNode);

测试结果:
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,60人围观)

还没有评论,来说两句吧...

相关阅读

    相关

    网上的递归遍历代码很多,这里就不赘述了,说一下思考的角度: 1. 把每一个棵子树都看成是独立的树; 2. 每一个节点都会把递归的代码重新执行一次; 3. 想象压栈的过程

    相关

    二叉树又称为红黑树,是一种常用的数据结构,而二叉树的遍历则是一种非常基本的操作。遍历二叉树的方式有两大类:递归和非递归。递归方式算法较为简便,并且更便于理解,非递归方式则需要对

    相关 ()——非

    1、前序遍历 根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同

    相关 实现

    1.二叉树前序遍历的非递归实现 \ 实现思路,先序遍历是要先访问根节点,然后再去访问左子树以及右子树,这明显是递归定义,但这里是用栈来实现的 \ 首先需要先从栈顶取出