`
kidneyball
  • 浏览: 329646 次
  • 性别: 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广告(推广投放)竞价页订单管理系统 一个...

    基于SpringBoot搭建的一个通用的OA管理系统,以车辆管理为例.zip

    基于SpringBoot搭建的一个通用的OA管理系统,以车辆管理为例 基于SpringBoot搭建的一个通用的OA管理系统,以车辆管理为例 基于SpringBoot搭建的一个通用的OA管理系统,以车辆管理为例 基于SpringBoot搭建的一个通用...

    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、本项目适合作为计算机、数学、电子信息等专业的课程设计...

    javascript 封装的一个通用的Ajax function

    封装的一个通用的Ajax function 可以直接进行调用,需要传入的参数:回调函数,跳转的地址,需要传入的参数,method(get或post),失败后调用的函数 例如: var onerror = function() { alert("error"); } var ...

    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