树与二叉树(Java语言实现)

本文介绍了二叉搜索树的概念,包括树和二叉树的基本定义,以及完全二叉树和平衡二叉树等类型。接着详细阐述了二叉搜索树的创建、插入、查找和删除节点的方法,并提供了相应的Java代码实现。最后,展示了二叉搜索树的先序、中序、后序和层次遍历的代码示例。
摘要由CSDN通过智能技术生成

本文实现代码地址:
https://github.com/helloWorldchn/DataStructure

一、树

树(Tree)是一种抽象数据类型(Abstract Data Type,ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

  • 每个节点都只有有限个子节点或无子节点;
  • 没有父节点的节点称为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 除了根节点外,每个子节点可以分为多个不相交的子树;
  • 树里面没有环路(cycle)

树的一些基本概念
(1)结点之间的关系描述

节点的祖先:从根到该节点所经分支上的所有节点;
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
兄弟节点:具有相同父节点的节点互称为兄弟节点;
堂兄弟节点:双亲在同一层的节点互为堂兄弟;

(2)结点、树的属性描述

结点的层次(深度):该节点从上往下数位于的层数
结点的高度:该节点从下往上数位于的层数
树的高度(深度):总共多少层
结点的度:有几个孩子(分支)
树的度:各结点的度的最大值

二、二叉树

二叉树(Binary Tree),是每个节点最多只有两个分支的树结构。通常分支被称作“左子树”和“右子树”。二叉树的分支具有左右次序,不能随意颠倒。二叉树示意图如下:
在这里插入图片描述

1.二叉树的性质

二叉树的第 i 层至多拥有 2 ( i − 1 ) 2^{(i−1)} 2(i1) 个节点;
深度为 h 的二叉树至多总共有 2 ( h + 1 ) − 1 2^{(h+1)}−1 2(h+1)1个节点

2.常见的二叉树

完全二叉树(Complete Binary Tree):对于一棵二叉树,假设其深度为 dd>1)。除了第 d 层外,其它各层的节点数目均已达最大值,且第 d 层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
在这里插入图片描述

满二叉树(Full Binary Tree):所有叶节点都在最底层的完全二叉树;
在这里插入图片描述

二叉搜索树(Binary Search Tree):也称二叉查找树,有序二叉树(Ordered Binary Tree)、排序二叉树(Sorted Binary Tree)。其特性为,对于任意节点,其左子树节点都小于该节点的值,并且其右子树节所有节点的值都大于该节点的值
在这里插入图片描述

平衡二叉树(AVL树):当且仅当任何节点的两棵子树的高度差不大于1的二叉树;
在这里插入图片描述

3.二叉树的创建(Java)

创建一个TreeNode类代表节点
TreeNode代表节点,每个TreeNode对象表示一个节点,left存放的是左子树,right存放的是右子树,val存放的是该节点的值。

// Definition for a binary tree node.
public class TreeNode {
	int val;
	TreeNode left;
	TreeNode right;
	TreeNode() {}
	TreeNode(int val) {
		this.val = val;
	}
	TreeNode(int val, TreeNode left, TreeNode right) {
		this.val = val;
		this.left = left;
		this.right = right;
	}
}

4.二叉树的遍历

以下图为例说明二叉树的遍历
在这里插入图片描述

4.1 二叉树的先序遍历(深度优先遍历)

先序遍历为根节点、左子树节点、右子树节点的顺序遍历,采用递归的方式。

如第一节图中的二叉搜索树所示的二叉树先序遍历为:7 1 0 5 3 2 4 6 9 8

	public void preOrderTraversal (TreeNode root) {
		if (root == null) {
			return;
		}
		System.out.print(root.val + " "); //先输出当前节点(初始的时候是root节点)
		preOrderTraversal(root.left); // 如果左子节点不为空,则递归继续前序遍历
		preOrderTraversal(root.right); // 如果右子节点不为空,则递归继续前序遍历
	}
4.2 二叉树的中序遍历(深度优先遍历)

中序遍历为左子树节点、根节点、右子树节点的顺序遍历,采用递归的方式。
如第一节图中的二叉搜索树所示的二叉树中序遍历为:0 1 2 3 4 5 6 7 8 9

	public void inOrderTraversa (TreeNode root) {
		if (root == null) {
			return;
		}
		inOrderTraversa(root.left); // 如果当前节点的左子节点不为空,则递归中序遍历
		System.out.print(root.val + " "); // 输出当前节点
		inOrderTraversa(root.right); // 如果当前的右子节点不为空,则递归中序遍历		
	}
	
4.3 二叉树的后序遍历(深度优先遍历)

后序遍历为左子树节点、右子树节点、根节点的顺序遍历,采用递归的方式。
如第一节图中的二叉搜索树所示的二叉树后序遍历为:0 2 4 3 6 5 1 8 9 7

	public void postOrderTraversal (TreeNode root) {
		if (root == null) {
			return;
		}
		postOrderTraversal(root.left); // 如果当前节点的左子节点不为空,则递归后序遍历
		postOrderTraversal(root.right); // 如果当前节点的右子节点不为空,则递归后序遍历
		System.out.print(root.val + " "); // 输出当前节点		
	}
4.4 二叉树的层次遍历(广度优先遍历)

层次遍历,即广度优先遍历,采用队列的方式实现。
如第一节图中的二叉搜索树所示的二叉树层次遍历为:7 1 9 0 5 8 3 6 2 4

    public void levelOrderTraversal(TreeNode root) {
    	if(root == null) {
    		return;
    	}    	
    	Queue<TreeNode> queue = new LinkedList<TreeNode>(); // 存放每层操作的根节点
        queue.offer(root);        
        while (!queue.isEmpty()) {
            int queueSize = queue.size();
            for (int i = 0; i < queueSize; i++) { // 用for循换可以隔离开每一层的遍历
            	TreeNode rootNode = queue.poll(); // 开始操作后将其从队列移除
            	System.out.print(rootNode.val + " ");
                if (rootNode.left != null) {
    	            TreeNode leftNode = rootNode.left; // 左节点存入队列,下一层遍历它就成了新根节点	            
    	            queue.offer(leftNode);
                }
                if (rootNode.right != null) {
                	TreeNode rightNode = rootNode.right; // 右节点存入队列,下一层遍历它就成了新根节点
                	queue.offer(rightNode);
                }
            }
        }
    }

三、案例完整代码

1.代码

BinaryTree 类:


import java.util.LinkedList;
import java.util.Queue;

public class BinaryTree {

    
	// 树的先序遍历
	public void preOrderTraversal (TreeNode root) {
		if (root == null) {
			return;
		}
		System.out.print(root.val + " "); //先输出当前节点(初始的时候是root节点)
		preOrderTraversal(root.left); // 如果左子节点不为空,则递归继续前序遍历
		preOrderTraversal(root.right); // 如果右子节点不为空,则递归继续前序遍历
	}
	
	// 树的中序遍历
	public void inOrderTraversa (TreeNode root) {
		if (root == null) {
			return;
		}
		inOrderTraversa(root.left); // 如果当前节点的左子节点不为空,则递归中序遍历
		System.out.print(root.val + " "); // 输出当前节点
		inOrderTraversa(root.right); // 如果当前的右子节点不为空,则递归中序遍历		
	}
	
	// 树的后序遍历
	public void postOrderTraversal (TreeNode root) {
		if (root == null) {
			return;
		}
		postOrderTraversal(root.left); // 如果当前节点的左子节点不为空,则递归后序遍历
		postOrderTraversal(root.right); // 如果当前节点的右子节点不为空,则递归后序遍历
		System.out.print(root.val + " "); // 输出当前节点		
	}

    // 广度优先遍历,即树的层次遍历,借用队列实现
    public void levelOrderTraversal(TreeNode root) {
    	if(root == null) {
    		return;
    	}    	
    	Queue<TreeNode> queue = new LinkedList<TreeNode>(); // 存放每层操作的根节点
        queue.offer(root);        
        while (!queue.isEmpty()) {
            int queueSize = queue.size();
            for (int i = 0; i < queueSize; i++) { // 用for循换可以隔离开每一层的遍历
            	TreeNode rootNode = queue.poll(); // 开始操作后将其从队列移除
            	System.out.print(rootNode.val + " ");
                if (rootNode.left != null) {
    	            TreeNode leftNode = rootNode.left; // 左节点存入队列,下一层遍历它就成了新根节点	            
    	            queue.offer(leftNode);
                }
                if (rootNode.right != null) {
                	TreeNode rightNode = rootNode.right; // 右节点存入队列,下一层遍历它就成了新根节点
                	queue.offer(rightNode);
                }
            }
        }
    }
	
	public static void main(String[] args) {
		TreeNode root;
		TreeNode node4 = new TreeNode(4);
		TreeNode node5 = new TreeNode(5);
		TreeNode node6 = new TreeNode(6);
		TreeNode node7 = new TreeNode(7);
		TreeNode node2 = new TreeNode(2, node4, node5);
		TreeNode node3 = new TreeNode(3, node6, node7);
		TreeNode node1 = new TreeNode(1, node2, node3);
		root = node1;

		BinaryTree binaryTree = new BinaryTree();
		System.out.print("先序遍历:");
		binaryTree.preOrderTraversal(root);
		System.out.println();
		System.out.print("中序遍历:");
		binaryTree.inOrderTraversa(root);
		System.out.println();
		System.out.print("后序遍历:");
		binaryTree.postOrderTraversal(root);
		System.out.println();
		System.out.print("层次遍历:");
		binaryTree.levelOrderTraversal(root);
		System.out.println();
	}
}

TreeNode类

//Definition for a binary tree node.
public class TreeNode {
	int val;
	TreeNode left;
	TreeNode right;
	TreeNode() {}
	TreeNode(int val) {
		this.val = val;
	}
	TreeNode(int val, TreeNode left, TreeNode right) {
		this.val = val;
		this.left = left;
		this.right = right;
	}
}

2.代码构建二叉树的模型

上面程序创建了如下图的二叉树:
在这里插入图片描述
上面二叉树的遍历结果依次是:
先序遍历:1 2 4 5 3 6 7
中序遍历:4 2 5 1 6 3 7
后序遍历:4 5 2 6 7 3 1
层次遍历:1 2 3 4 5 6 7

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

helloWorldZMY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值