二叉树学习记录

几种遍历规则

在这里插入图片描述

递归遍历和非递归遍历实现
递归遍历实现

原理也比较简单,直接看代码既可

public class Node {
	private int value;
	private Node leftNode;
	private Node rightNode;
	
	public Node(int value) {
		this.value = value;
	}
	public int getValue() {
		return value;
	}
	public void setValue(int value) {
		this.value = value;
	}
	public Node getLeftNode() {
		return leftNode;
	}
	public void setLeftNode(Node leftNode) {
		this.leftNode = leftNode;
	}
	public Node getRightNode() {
		return rightNode;
	}
	public void setRightNode(Node rightNode) {
		this.rightNode = rightNode;
	}
}

public class BinaryTree {
	// 前序
	public static void beforeTheOrder(Node node) {
		if (node == null) {
			return;
		}
		System.out.println(node.getValue());
		beforeTheOrder(node.getLeftNode());
		beforeTheOrder(node.getRightNode());
	}
	// 中序
	public static void middleTheOrder(Node node) {
		if (node == null) {
			return;
		}
		
		middleTheOrder(node.getLeftNode());
		System.out.println(node.getValue());
		middleTheOrder(node.getRightNode());
	}
	// 后序
	public static void afterTheOrder(Node node) {
		if (node == null) {
			return;
		}
		
		afterTheOrder(node.getLeftNode());
		afterTheOrder(node.getRightNode());
		System.out.println(node.getValue());
	}
	
	/**
			     1
			  /	     \
			2	      3
	      /    \    /    \
		 4	    5  6	  7
		  \        	     /
		   8            9
	*/
	public static class BinaryTreeBuilder {
		public static Node bulid() {
			Node n1 = new Node(1);
			Node n2 = new Node(2);
			Node n3 = new Node(3);
			Node n4 = new Node(4);
			Node n5 = new Node(5);
			Node n6 = new Node(6);
			Node n7 = new Node(7);
			Node n8 = new Node(8);
			Node n9 = new Node(9);
			n1.setLeftNode(n2);
			n1.setRightNode(n3);
			n2.setLeftNode(n4);
			n2.setRightNode(n5);
			n3.setLeftNode(n6);
			n3.setRightNode(n7);
			n4.setRightNode(n8);
			n7.setLeftNode(n9);
			return n1;
		}
	}
}

测试

public class BinaryTreeTest {
	public static void main(String[] args) {
		Node root = BinaryTree.BinaryTreeBuilder.bulid();
		System.out.println("前序------------");
		BinaryTree.beforeTheOrder(root);
		System.out.println("中序------------");
		BinaryTree.middleTheOrder(root);
		System.out.println("后序------------");
		BinaryTree.afterTheOrder(root);
		System.out.println("------------");
	}
}

测试结果

二叉树结构

			     1
			  /	     \
			2	      3
	      /    \    /    \
		 4	    5  6	  7
		  \        	     /
		   8            9
前序------------
1
2
4
8
5
3
6
7
9
中序------------
4
8
2
5
1
6
3
9
7
后序------------
8
4
5
2
6
9
7
3
1
------------

非递归遍历实现

前序遍历非递归实现
前序遍历思路,借助栈Stack实现。设初始化的时,将根结点放入栈中。

  1. 后续操作,只要将栈中元素出栈,输出当前元素
  2. 若子节点不为空,依次将右子节点、左子节点入栈
  3. 重复步骤1
    在这里插入图片描述
    对应代码实现
	public static void beforeTheOrder(Node node) {
		Stack<Node> stack = new Stack<>();
		stack.add(node);
		
		while (!stack.isEmpty()) {
			Node top = stack.pop();
			// 前序遍历,根节点优先输出
			System.out.println(top.getValue());
			
			Node rightNode = top.getRightNode();
			if (rightNode != null) {
				stack.push(rightNode);
			}
			Node leftNode = top.getLeftNode();
			if (leftNode != null) {
				stack.push(leftNode);
			}
		}
	}

中序遍历非递归实现
在这里插入图片描述
中序遍历思路,由于中序遍历根节点的有两种逻辑,我们只要通过变量区分此时根节点处于哪一种状态即可。

  • 定义A节点状态为0时,执行A->B逻辑
  • 定义A节点状态为1时,执行A->C逻辑

借助栈Stack实现,设初始化的时,将根结点放入栈中。

  1. 开始:从栈顶顶取出结点,假设当前顶部结点为A
  2. A节点状态为0
    • 判断当前A节点是否含有左节点,若有,入栈
    • 设置A节点状态为1
    • 从开始处重新执行
  3. A节点状态为1
    1. 输出当前节点
    2. 判断当前节点是否含有右节点,若有,入栈
    3. 从开始处重新执行
      对应代码实现
public class Node {
	private int value;
	private Node leftNode;
	private Node rightNode;
	/** 1:已访问,0:未访问 */
	private int flag;
	
	public Node(int value) {
		this.value = value;
	}
	public int getValue() {
		return value;
	}
	public void setValue(int value) {
		this.value = value;
	}
	public Node getLeftNode() {
		return leftNode;
	}
	public void setLeftNode(Node leftNode) {
		this.leftNode = leftNode;
	}
	public Node getRightNode() {
		return rightNode;
	}
	public void setRightNode(Node rightNode) {
		this.rightNode = rightNode;
	}
	public int getFlag() {
		return flag;
	}
	public void setFlag(int flag) {
		this.flag = flag;
	}
}

	public static void middleTheOrder(Node node) {
		Stack<Node> stack = new Stack<>();
		stack.add(node);
		
		while (!stack.isEmpty()) {
			Node peek = stack.peek();
			int flag = peek.getFlag();
			
			if (flag == 0) {
				// 本次访问
				peek.setFlag(1);
				Node leftNode = peek.getLeftNode();
				if (leftNode != null) {
					stack.add(leftNode);
				}
			} else if (flag == 1) {
				Node popNode = stack.pop();
				System.out.println(popNode.getValue());
				Node rightNode = popNode.getRightNode();
				if (rightNode != null) {
					stack.add(rightNode);
				}
			} 

		}
	}

后序遍历非递归实现
在这里插入图片描述
后续遍历思路和中序遍历思路一致,多一种状态而已,这里再分析,直接给出代码实现

	public static void afterTheOrder(Node node) {
		Stack<Node> stack = new Stack<>();
		stack.add(node);

		while (!stack.isEmpty()) {
			Node peek = stack.peek();
			int flag = peek.getFlag();

			if (flag == 0) {
				// 本次访问
				peek.setFlag(1);
				Node leftNode = peek.getLeftNode();
				if (leftNode != null) {
					stack.add(leftNode);
				}
			} else if (flag == 1) {
				peek.setFlag(2);
				Node rightNode = peek.getRightNode();
				if (rightNode != null) {
					stack.add(rightNode);
				}
			} else if (flag == 2) {
				Node popNode = stack.pop();
				System.out.println(popNode.getValue());
			}
		}
	}
层次遍历

在这里插入图片描述

广度遍历,直接使用Queue队列即可实现

	public static void traversal(Node node) {
		Queue<Node> queue = new LinkedBlockingDeque<>();
		queue.add(node);
		
		while (!queue.isEmpty()) {
			Node pollNode = queue.poll();
			System.out.println(pollNode.getValue());
			Node leftNode = pollNode.getLeftNode();
			if (leftNode != null) {
				queue.add(leftNode);
			}
			Node rightNode = pollNode.getRightNode();
			if (rightNode != null) {
				queue.add(rightNode);
			}
		}
	}
已知两种遍历顺序,画图

两种方式都是先找出根节点,再确定左节点,右节点

前序:GDAFEMHZ
中序:ADEFGHMZ

  1. 根据前序规则(GDAFEMHZ),我们可以确定根节点一定是G
  2. 根据中序遍历(ADEFGHMZ),可以根据根节点G左子树有ADEF节点,子树节点有HMZ节点
  3. 【左子树的确定】根据左子树有ADEF节点,我们去前序中查找,最先出现的一定是左子树有ADEF的根节点,根节点为D,递归,重复步骤二,查找剩下的结构
  4. 【右子树的确定】根据右子树有HMZ节点,我们去前序中查找,最先出现的一定是右子树有HMZ的根节点,根节点为M,递归,重复步骤二,查找剩下的结构

上述经过第一层,我们可以确定

   G
 /   \
D     M

D、M的子节点确认与G的子树确认过程一致


中序遍历: ADEFGHMZ
后序遍历: AEFDHZMG

这里的关键是后续遍历,后续遍历可以确定根节点G,推理和上述相同,不同的是通过前序还是后续来确定根节点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值