`
kidneyball
  • 浏览: 329288 次
  • 性别: Icon_minigender_1
  • 来自: 南太平洋
社区版块
存档分类
最新评论

一个通用的TreeIterator

 
阅读更多
因工作需要,写了一个通用的树迭代器。主体逻辑参考了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
	{}

}
1
1
分享到:
评论

相关推荐

    一个通用的PHP广告(推广投放)竞价页订单管理系统.zip

    一个通用的PHP广告(推广投放)竞价页订单管理系统 一个通用的PHP广告(推广投放)竞价页订单管理系统 一个通用的PHP广告(推广投放)竞价页订单管理系统 一个通用的PHP广告(推广投放)竞价页订单管理系统 一个...

    Nvme通用驱动 64 Nvme通用驱动 64

    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基于SpringBoot搭建的一个通用的OA管理系统源码.zip基于...

    设计一个通用寄存器组,16位的寄存器。(含报告)

    设计一个通用寄存器组,满足以下要求: ①通用寄存器组中有4个16位的寄存器。 ②当复位信号reset=0时,将通用寄存器组中的4个寄存器清零。 ③通用寄存器组中有1个写入端口,当DRWr=1时,在时钟clk的上升沿将数据总线...

    java 基于泛型与反射的通用 DAO

    本文将深入探讨如何结合这两种技术实现一个通用的DAO(Data Access Object)设计模式。 首先,我们来看“泛型”。泛型是Java 5引入的新特性,它允许在类、接口和方法中使用类型参数,从而提高了代码的类型安全性和...

    易语言通用脱壳机 易语言通用脱壳机 易语言通用脱壳机

    然后我就写了一个基于此的通用脱壳机. 目前支持易语言的两种编译方式 独立编译 和非独立编译.自动识别并修复数据. 特别是独立编译支持相对来说有那么一点用处.因为如果你要Patch人家的程序.你当然希望Patch完以后...

    基于Python实现的一个通用的二进制数据分析工具源码+文档说明(下载即用).zip

    基于Python实现的一个通用的二进制数据分析工具源码+文档说明(下载即用).zip分析任意格式的二进制数据,还能同时查看协议文档。 基于Python实现的一个通用的二进制数据分析工具源码+文档说明(下载即用).zip分析...

    易语言直接使用通用型

    "子程序1"可能是指一个示例子程序,用于演示如何在易语言中使用通用型。 5. **强制转换**:在处理通用型数据时,由于通用型可以存储任意类型,因此需要进行强制转换来确保数据的安全性和准确性。易语言提供了相应的...

    一个通用的Java线程池类

    环境:Windows XP ...这里本人翻写一个通用的线程池类,它可以用来作为工具类处理许多多线程问题。代码注释非常详尽,一行注释一行代码。 阅读对象:非常熟悉Java的基本概念,并且熟悉命令行编写代码的人员。

    基于SpringBoot+FreeMarker+MyBatis+ExtJs的一个通用后台管理系统源码(适合快速迭代开发).zip

    1、基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统源码(适合快速迭代开发).zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计...

    Nvme通用驱动 32 Nvme通用驱动 32

    Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme通用驱动 32Nvme...

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统,界面美观,适合快速迭代开发

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统,界面美观,适合快速迭代开发 项目说明 技术栈: SpringBoot MyBatis Redis MySQL FreeMarker ExtJs 基于SpringBoot+FreeMarker+MyBatis+...

    全局组,通用组,和域本地组的区别

    通用组比全局组的范围更广,它们可以跨越多个域,属于同一个目录林中的任何域。这意味着通用组可以包含不同域中的用户和联系人,提供跨域的权限分配。然而,虽然通用组可以跨域,但它们并不自动传播成员身份信息到...

    angularjs的一个通用模板

    angularjs的一个通用模板,稍微修改一下即可用作你的课程设计什么的

    封装一个通用Dialog,使用DialogFragment

    本教程将详细介绍如何封装一个通用的Dialog,使用DialogFragment。 1. **DialogFragment简介** DialogFragment是Fragment的子类,它具有Fragment的所有特性,如生命周期管理、回退栈支持等。同时,它还能展示一个...

    AxureUX WEB端交互原型通用组件模板库 v3

    AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) AxureUX WEB端交互原型通用组件模板库 v3 (组件列表) ...

    浅谈MyBatis通用Mapper实现原理

    MyBatis通用Mapper是MyBatis框架中的一种通用Mapper实现方式,主要提供了一些通用的方法,这些方法是以接口的形式提供的。通用Mapper的实现原理主要是通过Java反射机制和MyBatis框架的特点来实现的。 首先,通用...

    一个通用的动态链接库类

    一个通用的动态链接库类,附带范例程序。

    C#官方通用类库及通用数据库类库

    2. 用数据库类库 DC.CommonDbLiteLib针对SqlServer,MySQL,SQLite,Oracle,ODBC,OleDb,Firebird,PostgreSql,DB2,Informix,SqlServerCe连接进行了封装,一般情况下只需要调用一个IDatabaseInfo接口即可使用,...

Global site tag (gtag.js) - Google Analytics