左神算法笔记: 5. 二叉树的基本算法

二叉树不能形成环

  1. 先序、中序、后序遍历
    先序:对任意一个子树的处理顺序,都是先头结点、再左子树、再右子树
    中序:左头右
    后序:左右头
    [image:710374ED-4483-43C6-8740-52B0AB1597BA-22873-00006BA364335C85/iShot2020-12-18 20.40.44.png]
  2. 非递归方式实现二叉树的先序、中序、后序
    1. 任何递归函数都可以改成非递归
    2. 自己设计压栈的来实现
      • 先序实现逻辑:
        1. 放入head
        2. 循环(如果栈不为空)
          1. 出栈为head
          2. 打印head
          3. 如果有右,压入右
          4. 如果有左,压入左
      • 后序的实现逻辑:后序等于头右左的倒叙 -> 准备两个栈,head出栈的时候不直接打印,而是放入第二个栈
        1. 放入head
        2. 循环(stack1不为空)
          1. 如果有左,压入s1
          2. 如果有右,压入s1
        3. 循环(stack2不为空)
          1. 打印
      • 中序的实现逻辑:
        1. 整条左边界依次入栈
        2. 弹出节点并打印,来到右树执行逻辑1
      • 一个栈实现后序遍历(跳过)
  3. 实现二叉树的按层遍历
    1. 其实就是宽度优先遍历,用 队列
    2. 可以通过设置flag变量的方式, 来发现某一层的结束
public static void level(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.value);
			if (cur.left != null) {
				queue.add(cur.left);
			}
			if (cur.right != null) {
				queue.add(cur.right);
			}
		}
	}
  1. 统计二叉树最宽的一行的宽度
    1. 方法一【使用map】:使用一个Map<Node, height> levelMap来记录每个节点所对应的高度
public static int maxWidthUseMap(Node head) {
		if (head == null) {
			return 0;
		}
		Queue<Node> queue = new LinkedList<>();
		queue.add(head);
		// key 在 哪一层,value
		HashMap<Node, Integer> levelMap = new HashMap<>();
		levelMap.put(head, 1);
		int curLevel = 1; // 当前你正在统计哪一层的宽度
		int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
		int max = 0;
		while (!queue.isEmpty()) {
			Node cur = queue.poll();
			int curNodeLevel = levelMap.get(cur);
			if (cur.left != null) {
				levelMap.put(cur.left, curNodeLevel + 1);
				queue.add(cur.left);
			}
			if (cur.right != null) {
				levelMap.put(cur.right, curNodeLevel + 1);
				queue.add(cur.right);
			}
			if (curNodeLevel == curLevel) {
				curLevelNodes++;
			} else {
				max = Math.max(max, curLevelNodes);
				curLevel++;
				curLevelNodes = 1;
			}
		}
		max = Math.max(max, curLevelNodes);
		return max;
	}
2. 方法二:其实并不在乎第几层,只在乎每行什么时候结束
	- Node nextEnd用来在循环本层的时候记录下一层的最右节点
	- Node curEnd用来记录在本层的最右节点,当cur = curEnd的时候进行当层节点的结算,准备进入下一层
		1. max = Math.max(max, curLevelNodes)
		2. curLevelNodes = 0
		3. curEnd = nextEnd 指向下一个最后节点
public static int maxWidthNoMap(Node head) {
		if (head == null) {
			return 0;
		}
		Queue<Node> queue = new LinkedList<>();
		queue.add(head);
		Node curEnd = head; // 当前层,最右节点是谁
		Node nextEnd = null; // 下一层,最右节点是谁
		int max = 0;
		int curLevelNodes = 0; // 当前层的节点数
		while (!queue.isEmpty()) {
			Node cur = queue.poll();
			if (cur.left != null) {
				queue.add(cur.left);
				nextEnd = cur.left;
			}
			if (cur.right != null) {
				queue.add(cur.right);
				nextEnd = cur.right;
			}
			curLevelNodes++;
			if (cur == curEnd) {
				max = Math.max(max, curLevelNodes);
				curLevelNodes = 0;
				curEnd = nextEnd;
			}
		}
		return max;
	}
  1. 二叉树的序列化和反序列化【不要忽略Null节点】
    1. 可以用先序或者中序或者后序或者按层遍历,来实现二叉树的序列化
    2. 用了什么方式序列化,就用什么方式反序列化
      序列化
      [image:4A49A2BC-1482-4ADC-B71D-461396CAF695-22873-00007B1F849017C5/iShot2020-12-19 10.19.36.png]
    • 先序:
public static void pres(Node head, Queue<String> ans) {
		if (head == null) {
			ans.add(null);
		} else {
			ans.add(String.valueOf(head.value));
			pres(head.left, ans);
			pres(head.right, ans);
		}
	}
- 按层
public static Queue<String> levelSerial(Node head) {
		Queue<String> ans = new LinkedList<>();
		if (head == null) {
			ans.add(null);
		} else {
			ans.add(String.valueOf(head.value));
			Queue<Node> queue = new LinkedList<Node>();
			queue.add(head);
			while (!queue.isEmpty()) {
				head = queue.poll(); // head 父   子
				if (head.left != null) {
					ans.add(String.valueOf(head.left.value));
					queue.add(head.left);
				} else {
					ans.add(null);
				}
				if (head.right != null) {
					ans.add(String.valueOf(head.right.value));
					queue.add(head.right);
				} else {
					ans.add(null);
				}
			}
		}
		return ans;
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值