因工作需要,写了一个通用的树迭代器。主体逻辑参考了AOM (www.operamasks.org)的ComponentIterator,作了以下改进:
1. 接受任意节点类型(泛型参数)
2. 加入了一个stack来跟踪parent (节点无需提供getParent)
3. 加入了一个函数接口来过滤子树
主类:
public abstract class TreeIterator<Node> implements Iterator<Node>
{
private Node root;
private Node current;
private Node next;
private Fun1<Node, Boolean> subTreeFilter;
private Map<Node, Iterator<Node>> iteratorMap = new IdentityHashMap<Node, Iterator<Node>>();
private Deque<Node> path = new ArrayDeque<Node>();
public TreeIterator(Node root, boolean includeRoot, Fun1<Node, Boolean> subTreeFilter)
{
this.root = root;
this.subTreeFilter = subTreeFilter;
if (includeRoot && isSubTreeAccepted(root))
{
current = next = root;
}
else
{
current = next = getNextNode(root);
}
this.subTreeFilter = subTreeFilter;
}
private boolean isSubTreeAccepted(Node c)
{
if (subTreeFilter != null && !subTreeFilter.apply(c)) return false;
return true;
}
public boolean hasNext()
{
if (next == null && current != null)
{
current = next = getNextNode(current);
}
return next != null;
}
public Node next()
{
if (!hasNext())
{
throw new NoSuchElementException();
}
Node result = next;
next = null;
return result;
}
public void remove()
{
throw new UnsupportedOperationException();
}
private Node getNextNode(Node node)
{
Iterator<Node> children = getChildren(node);
if (children != null)
{
while (children.hasNext())
{
Node next = children.next();
if (isSubTreeAccepted(next))
{
iteratorMap.put(node, children);
path.push(node);
return next;
}
}
}
if (node == root)
{
return null;
}
Node next;
while ((next = getNextSibling(node)) == null)
{
node = path.pop();
if (node == null || node == root) return null;
}
return next;
}
private Node getNextSibling(Node node)
{
Node parent = path.peek();
if (parent == null)
{
return null;
}
Iterator<Node> children = iteratorMap.get(parent);
Node result = null;
if (children != null)
{
while (children.hasNext())
{
Node next = children.next();
if (isSubTreeAccepted(next))
{
result = next;
break;
}
}
}
if (result == null)
{
iteratorMap.remove(parent);
}
return result;
}
protected abstract Iterator<Node> getChildren(Node node);
}
Filter辅助类(用于过滤子树)
public abstract class Fun1<P1, R>
{
protected abstract R f (P1 arg0) throws Exception;
public final R apply(P1 arg0) {
try {
return f(arg0);
} catch(Exception e) {
throw new FunctionException(e);
}
}
}
public class FunctionException extends RuntimeException
{
private static final long serialVersionUID = 1L;
public FunctionException()
{
super();
}
public FunctionException(String message, Throwable cause)
{
super(message, cause);
}
public FunctionException(String message)
{
super(message);
}
public FunctionException(Throwable cause)
{
super(cause);
}
}
UnitTest (用法参考)
public class TreeIteratorTest
{
class TreeNode {
private String value;
private List<TreeNode> children;
public TreeNode(String value, TreeNode... children)
{
super();
this.value = value;
this.children = Arrays.asList(children);
}
public TreeNode(String value)
{
super();
this.value = value;
this.children = null;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
public List<TreeNode> getChildren()
{
return children;
}
public void setChildren(List<TreeNode> children)
{
this.children = children;
}
@Override
public String toString()
{
return "TreeNode [value=" + value + "]";
}
}
private TreeNode root;
private TreeNode node(String value) {
return new TreeNode(value);
}
private TreeNode node(String value, TreeNode... nodes) {
return new TreeNode(value, nodes);
}
class TreeNodeIterator extends TreeIterator<TreeNode> {
public TreeNodeIterator(TreeNode root, boolean includeRoot, Fun1<TreeNode, Boolean> subTreeFilter)
{
super(root, includeRoot, subTreeFilter);
}
@Override
protected Iterator<TreeNode> getChildren(TreeNode node)
{
return node.getChildren() != null ? node.getChildren().iterator() : null;
}
}
@Before
public void setUp() throws Exception
{
root = node("root",
node("child1",
node ("child11"),
node ("child12")),
node("child2"),
node("child3",
node ("child31"),
node ("child32",
node("child321"),
node("child322")),
node ("child33"))
);
}
@Test
public void testFullScan() throws Exception
{
TreeNodeIterator it = new TreeNodeIterator(root, true, null);
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next().getValue()).append('|');
}
assertEquals("root|child1|child11|child12|child2|child3|child31|child32|child321|child322|child33|", sb.toString());
}
@Test
public void testFullScanWithoutRoot() throws Exception
{
TreeNodeIterator it = new TreeNodeIterator(root, false, null);
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next().getValue()).append('|');
}
assertEquals("child1|child11|child12|child2|child3|child31|child32|child321|child322|child33|", sb.toString());
}
@Test
public void testFullScanWithoutBranch3() throws Exception
{
TreeNodeIterator it = new TreeNodeIterator(root, false, new Fun1<TreeNode, Boolean>() {
@Override protected Boolean f(TreeNode arg0) throws Exception
{
return !arg0.value.equals("child3");
}});
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next().getValue()).append('|');
}
assertEquals("child1|child11|child12|child2|", sb.toString());
}
@Test
public void testFullScanWithoutBranch32() throws Exception
{
TreeNodeIterator it = new TreeNodeIterator(root, false, new Fun1<TreeNode, Boolean>() {
@Override protected Boolean f(TreeNode arg0) throws Exception
{
return !arg0.value.equals("child32");
}});
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next().getValue()).append('|');
}
assertEquals("child1|child11|child12|child2|child3|child31|child33|", sb.toString());
}
@Test
public void testFullScanSingleNode() throws Exception
{
TreeNodeIterator it = new TreeNodeIterator(node("root"), true, null);
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next().getValue()).append('|');
}
assertEquals("root|", sb.toString());
}
@After
public void tearDown() throws Exception
{}
}
分享到:
相关推荐
一个通用的PHP广告(推广投放)竞价页订单管理系统 一个通用的PHP广告(推广投放)竞价页订单管理系统 一个通用的PHP广告(推广投放)竞价页订单管理系统 一个通用的PHP广告(推广投放)竞价页订单管理系统 一个...
Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme通用驱动 64Nvme...
基于SpringBoot搭建的一个通用的OA管理系统源码.zip基于SpringBoot搭建的一个通用的OA管理系统源码.zip基于SpringBoot搭建的一个通用的OA管理系统源码.zip基于SpringBoot搭建的一个通用的OA管理系统源码.zip基于...
设计一个通用寄存器组,满足以下要求: ①通用寄存器组中有4个16位的寄存器。 ②当复位信号reset=0时,将通用寄存器组中的4个寄存器清零。 ③通用寄存器组中有1个写入端口,当DRWr=1时,在时钟clk的上升沿将数据总线...
本文将深入探讨如何结合这两种技术实现一个通用的DAO(Data Access Object)设计模式。 首先,我们来看“泛型”。泛型是Java 5引入的新特性,它允许在类、接口和方法中使用类型参数,从而提高了代码的类型安全性和...
然后我就写了一个基于此的通用脱壳机. 目前支持易语言的两种编译方式 独立编译 和非独立编译.自动识别并修复数据. 特别是独立编译支持相对来说有那么一点用处.因为如果你要Patch人家的程序.你当然希望Patch完以后...
基于Python实现的一个通用的二进制数据分析工具源码+文档说明(下载即用).zip分析任意格式的二进制数据,还能同时查看协议文档。 基于Python实现的一个通用的二进制数据分析工具源码+文档说明(下载即用).zip分析...
"子程序1"可能是指一个示例子程序,用于演示如何在易语言中使用通用型。 5. **强制转换**:在处理通用型数据时,由于通用型可以存储任意类型,因此需要进行强制转换来确保数据的安全性和准确性。易语言提供了相应的...
环境:Windows XP ...这里本人翻写一个通用的线程池类,它可以用来作为工具类处理许多多线程问题。代码注释非常详尽,一行注释一行代码。 阅读对象:非常熟悉Java的基本概念,并且熟悉命令行编写代码的人员。
1、基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统源码(适合快速迭代开发).zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计...
Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme...
基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统,界面美观,适合快速迭代开发 项目说明 技术栈: SpringBoot MyBatis Redis MySQL FreeMarker ExtJs 基于SpringBoot+FreeMarker+MyBatis+...
通用组比全局组的范围更广,它们可以跨越多个域,属于同一个目录林中的任何域。这意味着通用组可以包含不同域中的用户和联系人,提供跨域的权限分配。然而,虽然通用组可以跨域,但它们并不自动传播成员身份信息到...
angularjs的一个通用模板,稍微修改一下即可用作你的课程设计什么的
本教程将详细介绍如何封装一个通用的Dialog,使用DialogFragment。 1. **DialogFragment简介** DialogFragment是Fragment的子类,它具有Fragment的所有特性,如生命周期管理、回退栈支持等。同时,它还能展示一个...
AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) ...
MyBatis通用Mapper是MyBatis框架中的一种通用Mapper实现方式,主要提供了一些通用的方法,这些方法是以接口的形式提供的。通用Mapper的实现原理主要是通过Java反射机制和MyBatis框架的特点来实现的。 首先,通用...
一个通用的动态链接库类,附带范例程序。
2. 用数据库类库 DC.CommonDbLiteLib针对SqlServer,MySQL,SQLite,Oracle,ODBC,OleDb,Firebird,PostgreSql,DB2,Informix,SqlServerCe连接进行了封装,一般情况下只需要调用一个IDatabaseInfo接口即可使用,...