算法基础07-二叉树基本算法

本文介绍了二叉树的基本算法,包括递归和非递归实现的先序、中序、后序遍历以及层序遍历。此外,还讨论了二叉树的序列化和反序列化方法,并提供了两个实战题目:返回二叉树的后继节点和折纸问题。通过中序遍历,可以找到二叉树中节点的后继节点,而折纸问题则可以通过理解折痕的规律,运用中序遍历解决。
摘要由CSDN通过智能技术生成

1 二叉树基本算法

1.1 二叉树的遍历

1.1.1 二叉树节点定义

    Class Node{
        // 节点的值类型
        V value;
        // 二叉树的左孩子指针
        Node left;
        // 二叉树的右孩子指针
        Node right;
    }

1.1.2 递归实现先序中序后序遍历

先序:任何子树的处理顺序都是,先头结点,再左子树,再右子树。先处理头结点

中序:任何子树的处理顺序都是,先左子树,再头结点,再右子树。中间处理头结点

后序:任何子树的处理顺序都是,先左子树,再右子树,再头结点。最后处理头结点

对于下面的一棵树:

graph TD
1-->2
1-->3
2-->4
2-->5
3-->6
3-->7

1、 先序遍历为:1 2 4 5 3 6 7

2、 中序遍历为:4 2 5 1 6 3 7

3、 后序遍历为:4 5 2 6 7 3 1

package class07;

public class Code01_RecursiveTraversalBT {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int v) {
			value = v;
		}
	}

	public static void f(Node head) {
		if (head == null) {
			return;
		}
		// 1 此处打印等于先序
		f(head.left);
		// 2 此处打印等于中序
		f(head.right);
		// 3 此处打印等于后序
	}

	// 先序打印所有节点
	public static void pre(Node head) {
		if (head == null) {
			return;
		}
		// 打印头
		System.out.println(head.value);
		// 递归打印左子树
		pre(head.left);
		// 递归打印右子树
		pre(head.right);
	}

        // 中序遍历
	public static void in(Node head) {
		if (head == null) {
			return;
		}
		in(head.left);
		System.out.println(head.value);
		in(head.right);
	}

        // 后序遍历
	public static void pos(Node head) {
		if (head == null) {
			return;
		}
		pos(head.left);
		pos(head.right);
		System.out.println(head.value);
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		head.right.right = new Node(7);

		pre(head);
		System.out.println("========");
		in(head);
		System.out.println("========");
		pos(head);
		System.out.println("========");

	}

}

结论:对于树的递归,每个节点实质上会到达三次,例如上文的树结构,对于f函数,我们传入头结点,再调用左树再调用右树。实质上经过的路径为1 2 4 4 4 2 5 5 5 2 1 3 6 6 6 3 7 7 7 3 1。我们在每个节点三次返回的基础上,第一次到达该节点就打印,就是先序,第二次到达该节点打印就是中序,第三次到达该节点就是后序。

所以先序中序后序,只是我们的递归顺序加工出来的结果!

1.1.3 非递归实现先序中序后序遍历(DFS)

思路:由于任何递归可以改为非递归,我们可以使用压栈来实现,实质就是深度优先遍历(DFS)。用先序实现的步骤,其他类似:

步骤一,把节点压入栈中,弹出就打印

步骤二,如果有右孩子先压入右孩子

步骤三,如果有左孩子压入左孩子

package class07;

import java.util.Stack;

public class Code02_UnRecursiveTraversalBT {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int v) {
			value = v;
		}
	}

        // 非递归先序
	public static void pre(Node head) {
		System.out.print("pre-order: ");
		if (head != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.add(head);
			while (!stack.isEmpty()) {
			  // 弹出就打印
				head = stack.pop();
				System.out.print(head.value + " ");
				// 右孩子不为空,压右
				if (head.right != null) {
					stack.push(head.right) ;
				}
				// 左孩子不为空,压左
				if (head.left != null) {
					stack.push(head.left);
				}
			}
		}
		System.out.println();
	}

        // 非递归中序
	public static void in(Node head) {
		System.out.print("in-order: ");
		if (head != null) {
			Stack<Node> stack = new Stack<Node>();
			while (!stack.isEmpty() || head != null) {
			  // 整条左边界依次入栈
				if (head != null) {
					stack.push(head);
					head = head.left;
				// 左边界到头弹出一个打印,来到该节点右节点,再把该节点的左树以此进栈
				} else {
					head = stack.pop();
					System.out.print(head.value + " ");
					head = head.right;
				}
			}
		}
		System.out.println();
	}

        // 非递归后序
	public static void pos1(Node head) {
		System.out.print("pos-order: ");
		if (head != null) {
			Stack<Node> s1 = new Stack<Node>();
			// 辅助栈
			Stack<Node> s2 = new Stack<Node>();
			s1.push(head);
			while (!s1.isEmpty()) {
				head = s1.pop();
				s2.push(head);
				if (head.left != null) {
					s1.push(head.left);
				}
				if (head.right != null) {
					s1.push(head.right);
				}
			}
			while (!s2.isEmpty()) {
				System.out.print(s2.pop().value + " ");
			}
		}
		System.out.println();
	}

        // 非递归后序2:用一个栈实现后序遍历,比较有技巧
	public static void pos2(Node h) {
		System.out.print("pos-order: ");
		if (h != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.push(h);
			Node c = null;
			while (!stack.isEmpty()) {
				c = stack.peek();
                //当做左树有没有处理的逻辑来看
				if (c.left != null && h != c.left && h != c.right) {
					stack.push(c.left);
                    //当做右树有没有处理的逻辑来看
				} else if (c.right != null && h !&#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值