用 Java 流的方式实现树型结构

在Java中,流(Stream)是一种处理集合数据的高级抽象,它提供了一种优雅且功能强大的方式来处理集合。当我们面对树型结构时,例如树(Tree)或图(Graph),使用流的方式可以使代码更为清晰、简洁,同时充分发挥Java 8引入的函数式编程特性。

下面将详细讲述一下如何利用Java流的方式来实现树型结构。

1. 树的节点定义

首先,我们需要定义树的节点。每个节点通常包含一个数据元素和指向其子节点的引用。我们使用一个简单的节点类来表示树的基本结构:

class TreeNode<T> {private T data;private List<TreeNode<T>> children;public TreeNode(T data) {this.data = data;this.children = new ArrayList<>();}public T getData() {return data;}public List<TreeNode<T>> getChildren() {return children;}public void addChild(TreeNode<T> child) {children.add(child);}
}

在这个类中,TreeNode 包含了一个泛型类型的数据元素和一个子节点列表。通过addChild方法,我们可以方便地向节点添加子节点。

2. 构建树结构

现在,我们来构建一个简单的树结构。假设我们要创建一个表示文件系统的树,其中每个节点表示一个目录,并包含其子目录和文件。我们可以按照如下方式构建这个树:

// 构建文件系统树
TreeNode<String> root = new TreeNode<>("root");TreeNode<String> documents = new TreeNode<>("Documents");
documents.addChild(new TreeNode<>("Resume.docx"));
documents.addChild(new TreeNode<>("Reports"));TreeNode<String> pictures = new TreeNode<>("Pictures");
pictures.addChild(new TreeNode<>("Vacation.jpg"));
pictures.addChild(new TreeNode<>("Family"));root.addChild(documents);
root.addChild(pictures);

这样,我们就创建了一个包含根目录、文档目录和图片目录的简单文件系统树。

3. 使用流遍历树

接下来,我们将使用Java流的方式来遍历这个树。首先,我们可以使用递归方式实现深度优先遍历:

// 深度优先遍历
public static <T> Stream<TreeNode<T>> flattenTree(TreeNode<T> root) {return Stream.concat(Stream.of(root),root.getChildren().stream().flatMap(TreeExample::flattenTree));
}// 示例用法
flattenTree(root).forEach(node -> System.out.println(node.getData()));

上述代码中,flattenTree 方法通过递归地将当前节点和其子节点展平为一个流。然后,我们使用 forEach 方法遍历流中的每个节点并打印其数据。

除了深度优先遍历,我们还可以实现宽度优先遍历:

// 宽度优先遍历
public static <T> Stream<TreeNode<T>> breadthFirstTraversal(TreeNode<T> root) {Queue<TreeNode<T>> queue = new LinkedList<>();queue.add(root);return Stream.generate(() -> {TreeNode<T> node = queue.poll();if (node != null) {queue.addAll(node.getChildren());}return node;}).takeWhile(Objects::nonNull);
}// 示例用法
breadthFirstTraversal(root).forEach(node -> System.out.println(node.getData()));

在这个例子中,breadthFirstTraversal 方法使用队列来实现宽度优先遍历。我们使用 generate 方法创建一个无限流,每次从队列中取出一个节点,并将其子节点加入队列。通过 takeWhile 方法,我们可以在流中保留非空节点。

4. 过滤和转换

使用流的方式,我们可以方便地进行过滤和转换操作。例如,假设我们要找到所有文件的节点,可以使用 filter 操作:

// 找到所有文件节点
List<TreeNode<String>> files = flattenTree(root).filter(node -> node.getData().contains(".")).collect(Collectors.toList());

上述代码中,我们通过 filter 方法筛选出包含点(.)的节点,即文件节点,并使用 collect 方法将结果收集到一个列表中。

同样,我们可以使用 map 操作进行节点数据的转换。例如,将所有文件节点的数据转换为大写:

// 转换所有文件节点的数据为大写
List<String> upperCaseFileNames = files.stream().map(node -> node.getData().toUpperCase()).collect(Collectors.toList());

5. 递归操作

在处理树型结构时,有时我们需要对每个节点及其子节点执行某个操作。这可以通过递归和流的方式实现。例如,假设我们要计算树的深度:

// 计算树的深度
public static <T> int calculateDepth(TreeNode<T> node) {return node.getChildren().stream().map(TreeExample::calculateDepth).max(Integer::compare).orElse(0) + 1;
}// 示例用法
int depth = calculateDepth(root);
System.out.println("Tree Depth: " + depth);

在这个例子中,calculateDepth 方法递归地计算每个子树的深度,并返回最大深度加一。通过使用流的 map 操作和 max 操作,我们可以方便地对每个子树的深度进行比较和聚合。

6. 并行流

Java流支持并行操作,这意味着我们可以轻松地将流操作转换为并行操作以提高性能。在树型结构中,这对于对多个子树进行独立操作的场景非常有用。

// 并行深度优先遍历
flattenTree(root).parallel().forEach(node -> System.out.println(Thread.currentThread().getName() + ": " + node.getData()));

在这个例子中,通过 parallel 方法将流转换为并行流,使得深度优先遍历可以并行进行。并行流的使用需要注意线程安全性,确保在并行执行的情况下,对共享数据的访问是安全的。

7. 自定义操作

流的方式允许我们定义自己的操作,以满足特定需求。例如,假设我们想要查找树中是否存在某个特定的节点:

// 查找节点
public static <T> Optional<TreeNode<T>> findNode(TreeNode<T> root, T target) {return flattenTree(root).filter(node -> node.getData().equals(target)).findFirst();
}// 示例用法
String targetNodeData = "Reports";
findNode(root, targetNodeData).ifPresent(node -> System.out.println("Node found: " + node.getData()));

在这个例子中,findNode 方法使用流的 filter 操作查找数据与目标值相等的节点,并使用 findFirst 获取第一个匹配的节点。这种自定义操作可以根据具体需求随意扩展。

8. 最后

使用Java流的方式来处理树型结构可以使代码更为清晰、简洁,同时充分发挥Java 8引入的函数式编程特性。通过深度优先遍历、宽度优先遍历以及各种过滤、转换和自定义操作,我们可以轻松地操作和处理树中的节点。并行流的使用还可以提高处理性能,特别是在大规模树结构的情况下。

当处理树型结构时,注意保持数据的一致性和线程安全性是非常重要的。确保在并行操作中,对共享数据的访问是安全的,并且对于可变状态的节点,需要采取适当的同步措施。

总的来说,使用Java流的方式处理树型结构是一种优雅而强大的编程范式,可以提高代码的可读性和可维护性。

黑马程序员Java零基础视频教程_上部(Java入门,含斯坦福大学练习题+力扣算法题和大厂java面试题)

黑马程序员Java零基础视频教程_下部(Java入门,含斯坦福大学练习题+力扣算法题和大厂java面试题)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/235911.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【分享】如何给Excel加密?码住这三种方法!

想要给Excel文件进行加密&#xff0c;方法有很多&#xff0c;今天分享三种Excel加密方法给大家。 打开密码 设置了打开密码的excel文件&#xff0c;打开文件就会提示输入密码才能打开excel文件&#xff0c;只有输入了正确的密码才能打开并且编辑文件&#xff0c;如果密码错误…

Elasticsearch常见面试题

文章目录 1.简单介绍下ES&#xff1f;2.简单介绍当前可以下载的ES稳定版本&#xff1f;3.安装ES前需要安装哪种软件&#xff1f;4.请介绍启动ES服务的步骤&#xff1f;5.ES中的倒排索引是什么&#xff1f;6. ES是如何实现master选举的&#xff1f;7. 如何解决ES集群的脑裂问题8…

高速视频采集卡设计方案:620-基于PCIe的高速视频采集卡

一、产品概述 基于PCIe的高速视频采集卡&#xff0c;通过PCIe3.0X8传输到存储计算服务器&#xff0c;实现信号的分析、存储。 北京太速科技 产品固化FPGA逻辑&#xff0c;适配视频连续采集&#xff0c;缓存容量2GB&#xff0c;开源的PCIe QT客户端软件&#xff0c…

(七)STM32 NVIC 中断、优先级管理及 AFIO 时钟的开启

目录 1. 中断相关知识简介 1.1 什么是中断 1.2 什么是内中断、外中断 1.3 什么是可屏蔽中断、不可屏蔽中断 2. CM3 内核中断介绍 2.1 F103系统异常清单 2.2 F103 外部中断清单 3. NVIC 简介 3.1 NVIC 寄存器简介 3.2 NVIC 相关寄存器的介绍 4. 中断优先级 4.1 优先…

2017年第六届数学建模国际赛小美赛B题电子邮件中的笔迹分析解题全过程文档及程序

2017年第六届数学建模国际赛小美赛 B题 电子邮件中的笔迹分析 原题再现&#xff1a; 笔迹分析是一种非常特殊的调查形式&#xff0c;用于将人们与书面证据联系起来。在法庭或刑事调查中&#xff0c;通常要求笔迹鉴定人确认笔迹样本是否来自特定的人。由于许多语言证据出现在电…

PyTorch深度学习实战(26)——卷积自编码器(Convolutional Autoencoder)

PyTorch深度学习实战&#xff08;26&#xff09;——卷积自编码器 0. 前言1. 卷积自编码器2. 使用 t-SNE 对相似图像进行分组小结系列链接 0. 前言 我们已经学习了自编码器 (AutoEncoder) 的原理&#xff0c;并使用 PyTorch 搭建了全连接自编码器&#xff0c;但我们使用的数据…

Co-DETR:基于协作混合分配训练的DETR

摘要 https://arxiv.org/pdf/2211.12860v5.pdf 本文观察到一个现象,即在DETR中使用一对一的集合匹配时,被分配为正样本的查询太少,导致对编码器输出的监督稀疏,这严重影响了编码器的判别特征学习,反之亦然,影响了解码器中的注意力学习。为了缓解这个问题,我们提出了一种…

C语言求回文数(详解版)

1、问题描述 打印所有不超过n&#xff08;取n<256&#xff09;的其平方具有对称性质的数&#xff08;也称回文数&#xff09;。 2、问题分析 对于要判定的数n计算出其平方后&#xff08;存于a&#xff09;&#xff0c;按照“回文数”的定义要将最高位与最低位、次高位与次…

Ubuntu2204一句话下载VSCode

参考链接:liunx系统下载VSCODE教程_linux下载vscode-CSDN博客 核心指令 sudo snap install --classic code 能在应用程序里面找到即可

【PHP入门】2.2 流程控制

-流程控制- 流程控制&#xff1a;代码执行的方向 2.2.1控制分类 顺序结构&#xff1a;代码从上往下&#xff0c;顺序执行。&#xff08;代码执行的最基本结构&#xff09; 分支结构&#xff1a;给定一个条件&#xff0c;同时有多种可执行代码&#xff08;块&#xff09;&am…

阿里推荐 LongAdder ,不推荐 AtomicLong !

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、CAS 1.1 CAS 全称 1.2 通俗理解CAS 1.3 CAS的问题 1.4 解决 ABA 问题 二、LongAdder 2.1 什么是 LongAdder 2.2 为什么推…

用JVS低代码实现业务流程的撤回和重新开始

在当今的数字化时代&#xff0c;业务流程的效率和准确性对于企业的运营至关重要。在实际业务场景中&#xff0c;我们可能需要处理一些复杂的流程&#xff0c;例如申请审批流程、合同签订流程等。这些流程在执行过程中可能会遇到各种情况&#xff0c;例如某个审批步骤需要重新审…

❀My虚拟机上的ftp服务器搭建(centos)❀

❀My虚拟机上的ftp服务器搭建(centos)❀ 在CentOS上搭建FTP服务器可以使用vsftpd软件&#xff0c;下面是详细的搭建教程&#xff1a; ①安装vsftpd软件 在终端中输入以下命令进行安装&#xff1a; sudo yum install vsftpd ②配置vsftpd 打开vsftpd的配置文件&#xff0c;…

【深度学习】序列生成模型(五):评价方法计算实例:计算BLEU-N得分【理论到程序】

文章目录 一、BLEU-N得分&#xff08;Bilingual Evaluation Understudy&#xff09;1. 定义2. 计算N1N2BLEU-N 得分 3. 程序 给定一个生成序列“The cat sat on the mat”和两个参考序列“The cat is on the mat”“The bird sat on the bush”分别计算BLEU-N和ROUGE-N得分(N1或…

WEB渗透—PHP反序列化(六)

Web渗透—PHP反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩…

Ubuntu 22.04 禁用(彻底移除)Snap

什么是Snaps Snaps 是 Ubuntu 的母公司 Canonical 于 2016 年 4 月发布 Ubuntu 16.04 LTS&#xff08;Long Term Support&#xff0c;长期支持版&#xff09;时引入的一种容器化的软件包格式。自 Ubuntu 16.04 LTS 起&#xff0c;Ubuntu 操作系统可以同时支持 Snap 及 Debian …

3dsmax渲染太慢,用云渲染农场多少钱?

对于许多从事计算机图形设计的创作者来说&#xff0c;渲染速度慢是一个常见问题&#xff0c;尤其是对于那些追求极致出图效果的室内设计师和建筑可视化师&#xff0c;他们通常使用3ds Max这样的工具&#xff0c;而高质量的渲染经常意味着长时间的等待。场景复杂、细节丰富&…

v-model 的原理

v-model是Vue.js框架中的一个指令&#xff0c;用于在表单元素和组件之间实现双向数据绑定。它提供了一种简洁的方式来将表单输入的值与Vue实例的属性进行关联。 当使用v-model指令时&#xff0c;Vue会根据表单元素的类型&#xff08;如input、select、textarea等&#xff09;自…

公共淋浴废水处理工艺流程及设备

公共淋浴废水处理工艺流程及设备 公共场所的淋浴废水含有有机物、污垢、清洁剂残留等污染物&#xff0c;如果直接排放到自然环境中&#xff0c;将对环境造成严重污染。为了有效处理这种废水&#xff0c;保护水资源和环境&#xff0c;制定一套完整的公共淋浴废水处理工艺流程&am…

APView500PV电能质量在线监测装置——安科瑞 顾烊宇

概述 APView500PV电能质量在线监测装置采用了高性能多核平台和嵌入式操作系统&#xff0c;遵照IEC61000-4-30《测试和测量技术-电能质量测量方法》中规定的各电能质量指标的测量方法进行测量&#xff0c;集谐波分析、波形采样、电压暂降/暂升/中断、闪变监测、电压不平衡度监测…