Java-树

devtools/2024/12/22 9:14:34/

一,树

1.1 概念

树是一种 非线性 数据结构,它是由 n n>=0 )个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看 起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
它具有以下的特点:
  • 有一个特殊的结点,称为根结点,根结点没有前驱结点
  • 除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1T2......Tm,其中每一个集合Ti (1 <= i <= m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
  • 树是递归定义的。

树中常用的一些概念:

结点的度 :一个结点含有子树的个数称为该结点的度;
树的度 :一棵树中,所有结点度的最大值称为树的度;
叶子结点或终端结点 :度为 0 的结点称为叶结点;
双亲结点或父结点 :若一个结点含有子结点,则这个结点称为其子结点的父结点;
孩子结点或子结点 :一个结点含有的子树的根结点称为该结点的子结点;
根结点 :一棵树中,没有双亲结点的结点;
结点的层次 :从根开始定义起,根为第 1 层,根的子结点为第 2 层,以此类推
树的高度或深度 :树中结点的最大层次;
非终端结点或分支结点 :度不为 0 的结点;
兄弟结点 :具有相同父结点的结点互称为兄弟结点; 
堂兄弟结点 :双亲在同一层的结点互为堂兄弟;
结点的祖先 :从根到该结点所经分支上的所有结点;
子孙 :以某结点为根的子树中任一结点都称为该结点的子孙。
森林 :由 m m>=0 )棵互不相交的树组成的集合称为森林
1.3 树的表示形式(了解)
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如: 双亲表示法 孩子表示法 孩子双亲表示法 孩子兄弟表示法 等等。我们这里就简单的了解其中最常用的 孩子兄弟表示法

一、双亲表示法

 
  1. 定义与原理

    • 用一组连续空间存储树的所有节点,同时在每个节点中,附设一个指示器指示其双亲节点在数组中的位置。
    • 也就是说,每个节点除了存储自身的数据信息外,还存储一个指向其双亲节点的指针(在这种情况下,用数组下标来表示指针)

二、孩子表示法

 
  1. 定义与原理

    • 把每个节点的孩子节点排列成一个单链表,称为孩子链表。n 个节点有 n 个孩子链表,如果是叶子节点,则此单链表为空。然后,n 个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。
    • 这种存储方式便于查找某个节点的孩子节点。

三、孩子双亲表示法

 
  1. 定义与原理

    • 结合了双亲表示法和孩子表示法的特点,既存储每个节点的孩子链表,又存储每个节点的双亲位置。

四、孩子兄弟表示法

 
  1. 定义与原理

    • 又称二叉树表示法,以二叉链表作为树的存储结构。链表中每个节点设两个指针域,分别指向该节点的第一个孩子节点和下一个兄弟节点。
    • 这种表示法使得任意一棵树都能转换为二叉树进行处理,方便实现各种树的操作。

 

二. 二叉树(重点)

2.1 概念

一棵二叉树是结点的一个有限集合,该集合:
1. 或者为空
2. 或者是由 个根节 点加上两棵别称为 左子树 右子树 的二叉树组成。

2.2 两种特殊的二叉树 

1. 满二叉树 : 一棵二叉树,如果 每层的结点数都达到最大值,则这棵二叉树就是满二叉树 。也就是说, 如果一棵 二叉树的层数为 K ,且结点总数是 ,则它就是满二叉树
2. 完全二叉树 : 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为 K 的,有 n个结点的二叉树,当且仅当其每一个结点都与深度为K 的满二叉树中编号从 0 n-1 的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树

 2.3 二叉树的性质

1. 若规定 根结点的层数为 1 ,则一棵 非空二叉树的第 i 层上最多有2^(i-1)
(i>0) 个结点
2. 若规定只有 根结点的二叉树的深度为 1 ,则 深度为 K 的二叉树的最大结点数是(2^k) - 1
(k>=0)
3. 对任何一棵二叉树 , 如果其 叶结点个数为 n0, 度为 2 的非叶结点个数为 n2, 则有 n0 n2 1
4. 具有 n 个结点的完全二叉树的深度 k 为 log 2(n+1) 上取整
5. 对于具有 n 个结点的完全二叉树 ,如果按照 从上至下从左至右的顺序对所有节点从 0 开始编号 ,则对于 序号为 i 的结点有
  1. i>0双亲序号:(i-1)/2i=0i为根结点编号,无双亲结点
  2. 2i+1<n,左孩子序号:2i+1,否则无左孩子
  3. 2i+2<n,右孩子序号:2i+2,否则无右孩子
二叉树的建立:
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int val) {this.val = val;}
}public void insert(int value) {root = insertRec(root, value);}private TreeNode insertRec(TreeNode root, int value) {if (root == null) {return new TreeNode(value);}if (value < root.val) {root.left = insertRec(root.left, value);} else if (value > root.val) {root.right = insertRec(root.right, value);}return root;}

2.4 二叉树的遍历:

//前序递归实现:public void preorderTraversalRec(TreeNode root) {if (root == null) {return;}System.out.print(root.val + " ");preorderTraversalRec(root.left);preorderTraversalRec(root.right);}
//前序非递归实现:public void preorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();System.out.print(node.val + " ");if (node.right!= null) {stack.push(node.right);}if (node.left!= null) {stack.push(node.left);}}}
//中序递归实现:public void inorderTraversalRec(TreeNode root) {if (root == null) {return;}inorderTraversalRec(root.left);System.out.print(root.val + " ");inorderTraversalRec(root.right);}
//中序非递归实现:public void inorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode current = root;while (current!= null ||!stack.isEmpty()) {while (current!= null) {stack.push(current);current = current.left;}current = stack.pop();System.out.print(current.val + " ");current = current.right;}}//后序递归实现:public void postorderTraversalRec(TreeNode root) {if (root == null) {return;}postorderTraversalRec(root.left);postorderTraversalRec(root.right);System.out.print(root.val + " ");}
//后序非递归实现:public void postorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode prev = null;TreeNode current = root;while (current!= null ||!stack.isEmpty()) {while (current!= null) {stack.push(current);current = current.left;}current = stack.peek();if (current.right == null || current.right == prev) {System.out.print(current.val + " ");stack.pop();prev = current;current = null;} else {current = current.right;}}}

以下是总代码:

import java.util.Stack;
import java.util.LinkedList;
import java.util.Queue;class TreeNode {char val;TreeNode left;TreeNode right;TreeNode(char val) {this.val = val;}
}
public class MyTree {// 获取树中节点的个数public int size(TreeNode root) {if (root == null) {return 0;}return 1 + size(root.left) + size(root.right);}// 获取叶子节点的个数public int getLeafTreeNodeCount(TreeNode root) {if (root == null) {return 0;}if (root.left == null && root.right == null) {return 1;}return getLeafTreeNodeCount(root.left) + getLeafTreeNodeCount(root.right);}// 获取第 K 层节点的个数public int getKLevelTreeNodeCount(TreeNode root, int k) {if (root == null || k < 1) {return 0;}if (k == 1) {return 1;}return getKLevelTreeNodeCount(root.left, k - 1) + getKLevelTreeNodeCount(root.right, k - 1);}// 获取二叉树的高度public int getHeight(TreeNode root) {if (root == null) {return 0;}int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);return Math.max(leftHeight, rightHeight) + 1;}// 检测值为 value 的元素是否存在public TreeNode find(TreeNode root, char val) {if (root == null) {return null;}if (root.val == val) {return root;}TreeNode leftResult = find(root.left, val);if (leftResult != null) {return leftResult;}return find(root.right, val);}// 层序遍历public void levelOrder(TreeNode root) {if (root == null) {return;}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {TreeNode node = queue.poll();System.out.print(node.val + " ");if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}}// 判断一棵树是不是完全二叉树public boolean isCompleteTree(TreeNode root) {if (root == null) {return true;}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);boolean flag = false;while (!queue.isEmpty()) {TreeNode node = queue.poll();if (node.left != null) {if (flag) {return false;}queue.add(node.left);} else {flag = true;}if (node.right != null) {if (flag) {return false;}queue.add(node.right);} else {flag = true;}}return true;}// 前序递归实现public void preorderTraversalRec(TreeNode root) {if (root == null) {return;}System.out.print(root.val + " ");preorderTraversalRec(root.left);preorderTraversalRec(root.right);}// 前序非递归实现public void preorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();System.out.print(node.val + " ");if (node.right != null) {stack.push(node.right);}if (node.left != null) {stack.push(node.left);}}}// 中序递归实现public void inorderTraversalRec(TreeNode root) {if (root == null) {return;}inorderTraversalRec(root.left);System.out.print(root.val + " ");inorderTraversalRec(root.right);}// 中序非递归实现public void inorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode current = root;while (current != null || !stack.isEmpty()) {while (current != null) {stack.push(current);current = current.left;}current = stack.pop();System.out.print(current.val + " ");current = current.right;}}// 后序递归实现public void postorderTraversalRec(TreeNode root) {if (root == null) {return;}postorderTraversalRec(root.left);postorderTraversalRec(root.right);System.out.print(root.val + " ");}// 后序非递归实现public void postorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode prev = null;TreeNode current = root;while (current != null || !stack.isEmpty()) {while (current != null) {stack.push(current);current = current.left;}current = stack.peek();if (current.right == null || current.right == prev) {System.out.print(current.val + " ");stack.pop();prev = current;current = null;} else {current = current.right;}}}}public class Test233 {public static void main(String[] args) {MyTree tree = new MyTree();TreeNode root = new TreeNode('A');root.left = new TreeNode('B');root.right = new TreeNode('C');root.left.left = new TreeNode('D');root.left.right = new TreeNode('E');System.out.println("前序遍历:");tree.preorderTraversalRec(root);System.out.println();System.out.println("中序遍历:");tree.inorderTraversal(root);System.out.println();System.out.println("后序遍历:");tree.postorderTraversal(root);System.out.println();TreeNode found = tree.find(root, 'A');if (found!= null) {System.out.println("找到了值为 A的节点");} else {System.out.println("未找到值为 A 的节点");}int treeHeight = tree.getHeight(root);System.out.println("树的高度为:" + treeHeight);}
}


http://www.ppmy.cn/devtools/109235.html

相关文章

ASP.NET Core 中间件

一、什么是中间件&#xff1f; 中间件 是一种装配到 ASP.NET Core 应用程序请求处理管道中的软件组件&#xff0c;用于处理 HTTP 请求和响应。 每个中间件组件可以&#xff1a; 选择是否将请求传递到下一个中间件&#xff1a;通过调用 next() 或者不调用 next() 来决定是否将…

IP学习——oneday

1.什么是网络&#xff1f;为什么需要网络&#xff1f; 空间&#xff0c;时间&#xff1b;传统的邮件传输要考虑到距离&#xff0c;网络解决了空间距离&#xff08;太远&#xff09;、解决了时间问题&#xff08;旧音乐等&#xff09; 云:面向客户的虚拟化服务 运营商公司主营…

SQL 支持使用 GROUP BY多个列

SQL 语言支持使用 GROUP BY 子句对多个列进行分组。当你对多个列进行分组时&#xff0c;SQL 会根据这些列的组合值来分组数据。这意味着只有当所有指定的列在多行中具有相同的值时&#xff0c;这些行才会被分组在一起。 语法 SELECT column1, column2, AGGREGATE_FUNCTION(co…

【JUC】同步器(AQS原理、ReentrantLock原理、ConcurrentHashMap原理)

文章目录 一、AQS原理1.1 AQS简介1.2 AQS原理1.3 CLH队列1.4 ASQ的设计1.4.1 设计原理1.4.2 state 设计1.4.3 封装线程的 Node 节点中 waitStatus 设计1.4.4 阻塞恢复设计1.4.5 队列设计为什么队列要设计成双向链表&#xff1f; 1.5 自定义同步器 二、**ReentrantLock 原理**2.…

当小程序遭遇攻击或超出流量峰值时:SCDN边缘加速的高效防护策略!

在数字化时代&#xff0c;小程序因其便捷性和丰富的功能而备受用户喜爱&#xff0c;但这也使其成为了网络攻击的目标之一。DDoS攻击、CC攻击等不仅会影响小程序的正常运行&#xff0c;还会损害用户体验和品牌形象。在这种情况下&#xff0c;选择合适的安全防护措施至关重要。边…

ffmpeg的安装和使用教程

在Linux上安装和使用FFmpeg可以方便地完成音视频的编码、解码、转码等操作。以下是详细的安装和使用教程。 安装FFmpeg FFmpeg的安装方法会因为不同的Linux发行版有所不同。下面是几种常见的安装方法&#xff1a; Ubuntu/Debian 打开终端&#xff0c;更新包列表并安装FFmpe…

springboot绘画艺术品在线交易商城管理系统---附源码87862

摘 要 随着互联网的快速发展&#xff0c;艺术品交易逐渐向线上平台转移&#xff0c;为了满足用户对绘画艺术品的需求&#xff0c;开发一个高效、安全、易用的在线交易商城管理系统变得尤为重要。 本文首先介绍了绘画艺术品在线交易商城管理系统的背景和重要性。然后&#xff0…

urllib与requests爬虫简介

urllib与requests爬虫简介 – 潘登同学的爬虫笔记 文章目录 urllib与requests爬虫简介 -- 潘登同学的爬虫笔记第一个爬虫程序 urllib的基本使用Request对象的使用urllib发送get请求实战-喜马拉雅网站 urllib发送post请求 动态页面获取数据请求 SSL证书验证伪装自己的爬虫-请求头…