二叉树的定义及遍历

本文回顾了数据结构中的二叉树概念,强调了二叉树在算法题中的重要性。介绍了二叉树节点的定义,以及如何创建二叉树。文章详细讲解了二叉树的三种遍历方式——先序、中序和后序,包括递归和非递归的实现方法,并指出深刻理解这些基础知识对于高效利用二叉树至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在刷算法题的过程中发现以前学过的一些数据结构方面的知识有些遗忘了,就开始复习数据结构。

在计算机科学中,二叉树(binaryTree)是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。

以下是关于二叉树的创建及其递归和非递归的三种遍历方式,在刷算法题的过程中发现二叉树可以运用在多种场景下,在运用得当的情况下可以极大提升程序的效率,但万丈高楼平地起,只有对二叉树基础定义、实现及遍历足够了解,才能将其运用得当。

  • 二叉树的结点定义类
class Node {
		 Node leftChild;
		 Node rightChild;
		 int data;
		 
		 Node(int data) {
			 leftChild = null;
			 rightChild = null;
			 this.data = data;
		 }
	 }
由于二叉树具有天然的递归结构,因此在二叉树的创建及遍历过程中使用递归是不错的方法。
  • 二叉树的创建
// 创建二叉树
	 public void createBinaryTree() {
		 nodeList = new ArrayList<>();
		 // 将数组中的值依次转化为二叉树的结点
		 for(int i = 0; i < array.length; i++) {
			 nodeList.add(new Node(array[i]));
		 }
		 for(int i = 0; i < array.length/2 - 1; i++) {
			 nodeList.get(i).leftChild = nodeList.get(2 * i + 1);
			 nodeList.get(i).rightChild = nodeList.get(2 * i + 2);
		 }
		 int lastIndex = array.length/2 - 1;
		 nodeList.get(lastIndex).leftChild = nodeList.get(2 * lastIndex + 1);
		 // 判断是否有右节点
		 if(array.length % 2 == 1) {
			 nodeList.get(lastIndex).rightChild = nodeList.get(2 * lastIndex + 2);
		 }
	 }

二叉树的遍历方式分为先序、中序及后续遍历,每种遍历方式都可以通过递归和非递归两种方式完成

递归方式的先序、中序及后续遍历
// 先序遍历
	 public static void preOrderTraverse(Node node) {
		 if(node == null) {
			 return;
		 }
		 System.out.print(node.data + " ");
		 preOrderTraverse(node.leftChild);
		 preOrderTraverse(node.rightChild);
	 }
	 
	 // 中序遍历
	 public static void inOrderTraverse(Node node) {
		 if(node == null) {
			 return;
		 }
		 inOrderTraverse(node.leftChild);
		 System.out.print(node.data + " ");
		 inOrderTraverse(node.rightChild);
	 }
	 
	 // 后序 遍历
	 public static void afterOrderTraverse(Node node) {
		 if(node == null) {
			 return;
		 }
		 afterOrderTraverse(node.leftChild);
		 afterOrderTraverse(node.rightChild);
		 System.out.print(node.data + " ");
	 }
非递归方式的先序、中序及后续遍历
// 非递归前序遍历
	 public static void preOrder(Node node) {
		 if(node == null) {
			 return ;
		 }
		 Node temp = node;
		 Stack<Node> s = new Stack<>();
		 // 根节点入栈
		 s.push(temp);
		 while(!s.isEmpty()) {
			 // 1. 访问根节点
			 Node pop = s.pop();
			 System.out.print(pop.data + " ");
			 // 2. 若根节点存在右孩子结点,将其入栈
			 if(pop.rightChild != null) {
				 s.push(pop.rightChild);
			 }
			// 3. 若根节点存在左孩子结点,将其入栈
			 if(pop.leftChild != null) {
				 s.push(pop.leftChild);
			 }
		 }
	 }
	 
	 // 非递归中序遍历
	 public static void inOrder(Node node) {
		 if(node == null) {
			 return ;
		 }
		 Node temp = node;
		 Stack<Node> s = new Stack<>();
		 while(temp != null || !s.isEmpty()) {
			 // 1. 将根节点入栈
			 // 2. 将所有左孩子入栈
			 while(temp != null) {
				 s.push(temp);
				 temp = temp.leftChild;
			 }
			 // 3. 访问栈顶元素
			 temp = s.pop();
			 System.out.print(temp.data + " ");
			 // 4. 若栈顶元素存在右孩子结点,则将右孩子赋值给temp,也就是将右孩子入栈
			 if(temp.rightChild != null) {
				 temp = temp.rightChild;
			 }else {
				 temp = null;
			 }
		 }
	 }
	 
	 // 非递归后序遍历
	 public static void afterOrder(Node node) {
		 if(node == null) {
			 return ;
		 }
		 // 当前结点
		 Node temp = node;
		 // 上一次访问的结点;
		 Node prev = null;
		 Stack<Node> s = new Stack<>();
		 while(temp != null || !s.isEmpty()) {
			 // 1. 将根结点及其左孩子入栈
			 while(temp != null) {
				 s.push(temp);
				 temp = temp.leftChild;
			 }
			 if(!s.isEmpty()) {
				 // 2. 获取栈顶元素值
				 temp = s.peek();
				 // 3. 没有右孩子,或者右孩子已经被访问过
				 if(temp.rightChild == null || temp.rightChild == prev) {
					 temp = s.pop();
					 System.out.print(temp.data + " ");
					 // 标记上一次访问的结点
					 prev = temp;
					 temp = null;
				 }else {
					 // 存在没有被访问的右孩子
					 temp = temp.rightChild;
				 }
			 }
		 }
	 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值