树的先序、中序、后序和宽度遍历方式

递归序列的认识(太重要了!!!)

在这里插入图片描述
上图就是左侧时一颗树,右上是递归序,下方是三种遍历方式,先序、中序和后序,那么如何从递归序变成下面三种遍历方式呢?

  • 先序遍历就是递归序中只打印第一次到出现的数字
  • 中序遍历就是递归序中只打印第二次到出现的数字
  • 后序遍历就是递归序中只打印第三次到出现的数字

对应我们经常看到的代码

public static void treeLoop(Node head){
        if(head == null){
            return;
        }
        //一进来,当前位置就是自己的位置
        //第一次打印自己
        System.out.println(head.val);
        //访问左子树
        treeLoop(head.left);
        //左子树访问完毕,回到自己
        //第二次打印自己
        System.out.println(head.val);
        //访问右子树
        treeLoop(head.right);
        //右子树访问完毕,回到自己
        //第三次打印自己
        System.out.println(head.val);
    }

所以说为什么下面先序遍历、中序遍历、后序遍历只是改变打印位置,然后就是对应的遍历方式,就是这个原因

树的遍历

递归方式

1、先序遍历(头->左->右)

    public static void treeLoop(Node head){
        if(head == null){
            return;
        }
        System.out.println(head.val);
        treeLoop(head.left);
        treeLoop(head.right);
    }

2、中序遍历(左->头->右)

    public static void treeLoop(Node head){
        if(head == null){
            return;
        }
        treeLoop(head.left);
        System.out.println(head.val);
        treeLoop(head.right);
    }

3、后序遍历(左->右->头)

    public static void treeLoop(Node head){
        if(head == null){
            return;
        }
        treeLoop(head.left);
        treeLoop(head.right);
        System.out.println(head.val);
    }

递归方式就是打印位置不一样,是根据递归序而来的,需要用哪种遍历方式,就在对应位置做想做的事事情

非递归方式

1、先序遍历
思路:申请一个栈,每次先把一个元素放入栈中,如果栈不为空,从栈弹出一个元素,做事情,然后再把右孩子压栈,再把左孩子压栈

 public static void treeLoop(Node head){
        if(head != null){
	        Stack<Node> stack = new Stack<>();
	        stack.add(head);
	        while(!stack.isEmpty()){
	            Node pop = stack.pop();
	            System.out.println(pop);
	            if(head.right != null){
	                stack.push(head.right);
	            }
	            if(head.left != null){
	                stack.push(head.left);
	            }
	        }
        }
    }

2、中序遍历
每课子树左边界进栈,每次弹出一个元素,打印,并把当前元素的右子树的左边界进栈,周而复始

    public static void treeLoop(Node head){
        if(head != null){
            Stack<Node> stack = new Stack<>();
            //一开始栈为空,Node不为空,所以head不为空,可以进入while循环
            while(!stack.isEmpty() || head != null){
            	//所有左孩子进栈
                if(head != null){
                    stack.push(head);
                    head = head.left;
                } else {
                //弹出最后一个左孩子,打印(处理),再把最后一个左孩子的右孩子
                    head = stack.pop();
                    System.out.println(head.val + " ");
                    head = head.right;
                }
            }
        }
    }

3、后序遍历
思路:申请两个栈,一个栈和一个收集栈,先把第一个元素放入栈中,判断左栈是否为空,不为空,弹出一个元素,放入收集栈,再把左孩子和右孩子压入栈中,周而复始,最后输出辅助栈

public static void treeLoop(Node head){
        if(head != null){
            Stack<Node> s1 = new Stack<>(); //栈
            Stack<Node> s2 = new Stack<>(); //辅助栈
            s1.add(head);
            while(!s1.isEmpty()){
                Node pop = s1.pop();
                s2.push(pop);
                if(head.left != null){
                    s1.push(head.left);
                }
                if(head.right != null){
                    s1.push(head.right);
                }
            }
            while(!s2.isEmpty()){
                System.out.print(s2.pop().val + " ");
            }
        }
        System.out.println();
    }

宽度优先遍历(层次遍历)

思路:使用队列完成

    public static void treeLoop(Node head){
        if(head ==null){
            return;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        while(!queue.isEmpty()){
            Node cur = queue.poll();
            System.out.println(cur.val);
            if(cur.left != null){
                queue.add(cur.left);
            }
            if(cur.right != null){
                queue.add(cur.right);
            }
        }
    }
题目:

根据宽度优先遍历,求一课树最长的最大的宽度,null不算在内

    public static void treeLoop(Node head){
        if(head ==null){
            return;
        }
        Queue<Node> queue = new LinkedList<>();
        //存放节点和层级的map
        Map<Node,Integer> levelMap = new HashMap<>(); 
        levelMap.put(head,1);
        //当前在第几层,这个是全局增长的
        int curLevel = 1;
        //当前层有多少节点,这个没到一层就会重置
        int curLevelNodes = 0;
        //最大宽度
        int maxNodes = Integer.MIN_VALUE;
        queue.add(head);
        while(!queue.isEmpty()){
            Node cur = queue.poll();
            //判断当前节点是不是和我们层级一样
            if(curLevel == levelMap.get(cur)){
                curLevelNodes++;
            }else{
                maxNodes = Math.max(maxNodes,curLevelNodes);
                curLevel++;
                curLevelNodes = 1;
            }
            if(cur.left != null){
                //维护map
                levelMap.put(cur.left,curLevel + 1);
                queue.add(cur.left);
            }
            if(cur.right != null){
                //维护map
                levelMap.put(cur.right,curLevel + 1);
                queue.add(cur.right);
            }
        }
        //最后比较最后一层节点数量和我们最大节点比较,最后一层在上面未比较
        maxNodes = Math.max(maxNodes,curLevelNodes);
    }

以上所有内容是皆来自于算法课程
B站-左程云左神的教学视频

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是C语言实现的代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct node { char data; struct node* left; struct node* right; } Node; // 创建二叉 Node* createTree() { char ch; Node* root = NULL; scanf("%c", &ch); if (ch == '#') { root = NULL; } else { root = (Node*)malloc(sizeof(Node)); if (root == NULL) { printf("内存分配失败!\n"); exit(1); } root->data = ch; root->left = createTree(); root->right = createTree(); } return root; } // 计算二叉叶子节点数和总节点数 void countNodes(Node* root, int* count, int* leafCount) { if (root != NULL) { (*count)++; if (root->left == NULL && root->right == NULL) { (*leafCount)++; } countNodes(root->left, count, leafCount); countNodes(root->right, count, leafCount); } } // 二叉 void preOrder(Node* root) { if (root != NULL) { printf("%c ", root->data); preOrder(root->left); preOrder(root->right); } } // 二叉 void inOrder(Node* root) { if (root != NULL) { inOrder(root->left); printf("%c ", root->data); inOrder(root->right); } } // 后二叉 void postOrder(Node* root) { if (root != NULL) { postOrder(root->left); postOrder(root->right); printf("%c ", root->data); } } // 层次遍二叉 void levelOrder(Node* root) { Node* queue[1000]; int front = 0, rear = 0; queue[rear++] = root; while (front < rear) { Node* node = queue[front++]; printf("%c ", node->data); if (node->left != NULL) { queue[rear++] = node->left; } if (node->right != NULL) { queue[rear++] = node->right; } } } // 计算二叉的高度 int height(Node* root) { if (root == NULL) { return 0; } int leftHeight = height(root->left); int rightHeight = height(root->right); return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; } // 计算二叉宽度 int width(Node* root) { if (root == NULL) { return 0; } Node* queue[1000]; int front = 0, rear = 0, maxWidth = 0; queue[rear++] = root; while (front < rear) { int count = rear - front; if (count > maxWidth) { maxWidth = count; } while (count-- > 0) { Node* node = queue[front++]; if (node->left != NULL) { queue[rear++] = node->left; } if (node->right != NULL) { queue[rear++] = node->right; } } } return maxWidth; } int main() { printf("请输入二叉,使用'#'表示空节点:\n"); Node* root = createTree(); int count = 0, leafCount = 0; countNodes(root, &count, &leafCount); printf("二叉总节点数:%d,叶子节点数:%d\n", count, leafCount); printf("结果:"); preOrder(root); printf("\n"); printf("结果:"); inOrder(root); printf("\n"); printf("后结果:"); postOrder(root); printf("\n"); printf("层次遍结果:"); levelOrder(root); printf("\n"); printf("二叉的高度:%d\n", height(root)); printf("二叉宽度:%d\n", width(root)); return 0; } ``` 其,输入二叉方式为从标准输入读取字符,使用 # 表示空节点。在计算节点数和叶子节点数时,使用了指针传参的方式。在计算二叉高度和宽度时,使用了队列来实现层次遍

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值