遍历树的两种方式的测试及比较

节点类:java

/**
 * 节点类
 */
public class TreeNode {
	/**
	 * 节点编号
	 */
	public String id;
	/**
	 * 节点内容
	 */
	public String text;
	/**
	 * 父节点编号
	 */
	public String parentId;
	/**
	 * 孩子节点列表
	 */
	//private Children children = new Children();
	private List<TreeNode> children = new ArrayList<TreeNode>();

	// 添加孩子节点
	public void addChild(TreeNode node) {
		//this.children.addChild(node);
		this.children.add(node);
	}

	public List<TreeNode> getChildren() {
		return children;
	}
}

使用递归的方式遍历树并生成json字符串node

//使用递归的方式来遍历树
	private void travelByRecursion(TreeNode node, StringBuilder builder) {
		//dealnode
		//System.out.print("{" + "\"id\" : \"" + node.id + "\"" + ", \"text\" : \"" + node.text + "\"");
		builder.append("{" + "\"id\" : \"" + node.id + "\"" + ", \"text\" : \"" + node.text + "\"");
		List<TreeNode> children = node.getChildren();
		if (children != null && !children.isEmpty()) {
			//System.out.print(", \"children\" : [");
			builder.append(", \"children\" : [");
			for (Iterator<TreeNode> it = children.iterator(); it.hasNext();) {
				TreeNode n = it.next();
				travelByRecursion(n, builder);
				if (it.hasNext()) {
					//System.out.print(",");
					builder.append(',');
				}
				
			}
			//System.out.print("]");
			builder.append(']');
		} else {
			//System.out.print(", \"leaf\" : true");
			builder.append(", \"leaf\" : true");
		}
		//System.out.print("}");
		builder.append('}');
	}

使用循环的方式遍历树并生成json字符串json

//使用循环的方式来遍历树
	private void travelByCycle(TreeNode node, StringBuilder builder) {
		//定义一个先入后出的栈存放节点信息
		Stack<TreeNode> stack = new Stack<TreeNode>();
		//定义一个先入后出的栈存放节点的闭合符号
		Stack<String> closeSymbolStack = new Stack<String>();
		//定义一个散列表存放同一层节点的最后一个节点的信息(用于判断是否输出逗号),key为node的id,value为上一节点的id
		Map<String, String> latestNode = new HashMap<String, String>();
		stack.push(node);
		TreeNode lpNode;
		//根节点确定是同一层节点的最后一个节点,因此须要加入散列表
		latestNode.put(node.id, null);
		//int i=0;
		//closeSymbolStack.push("]}");
		//System.out.println(node.id);
		//i++;
		while (!stack.isEmpty()) {
			lpNode = stack.pop();
			//dealnode
			builder.append("{" + "\"id\" : \"" + lpNode.id + "\"" + ", \"text\" : \"" + lpNode.text + "\"");
			List<TreeNode> children = lpNode.getChildren();
			if (children != null && !children.isEmpty()) {
				builder.append(", \"children\" : [");
				boolean firstNode = true;
				TreeNode currentNode = null;
				for (Iterator<TreeNode> it = children.iterator(); it.hasNext();) {
					currentNode = it.next();
					if (firstNode) {
						//栈是先进后出的,因此在同一层级中第一个入栈的节点其实是最后一个被读取的节点也就是最后一个节点
						//System.out.println(currentNode.id + "," + lpNode.id);
						latestNode.put(currentNode.id, lpNode.id);
						firstNode = false;
					}
					stack.push(currentNode);
				}
				//往闭合符号栈中压入该节点对应的闭合符号
				//判断该节点是否为同一层节点的最后一个节点
				//若是不是同一层节点的最后一个节点则须要多输出一个逗号
				if (latestNode.containsKey(lpNode.id)) {
					//System.out.println(lpNode.id);
					closeSymbolStack.push("]}");
					//i++;
				} else {
					closeSymbolStack.push("]},");
				}
			} else {
				builder.append(", \"leaf\" : true}");
				//判断是滞是不是同一层节点的最后一个叶子节点
				
				if (!latestNode.containsKey(lpNode.id)) {
					//若是不是是同一层节点的最后一个叶子节点则输出逗号
					builder.append(',');
				} else {
					//若是是是同一层节点的最后一个叶子节点则输出闭合符号
					if (!closeSymbolStack.isEmpty()) {
						builder.append(closeSymbolStack.pop());
					}
					//若是是同一层节点的最后一个叶子节点则判断上一节点是不是最后一个节点,若是是则输出闭合符号,循环处理直到上一节点不是同层次的最后一个节点或上一节点为空
					String tempId = lpNode.id;
					String parendNodeId = latestNode.get(tempId);
					while (parendNodeId != null && latestNode.containsKey(parendNodeId)) {
						//System.out.println(tempId + "," + parendNodeId);
						if (!closeSymbolStack.isEmpty()) {
							builder.append(closeSymbolStack.pop());
						}
						tempId = parendNodeId;
						parendNodeId = latestNode.get(tempId);
					}
				}
			}
			
		}
		if (!closeSymbolStack.isEmpty()) {
			for (Iterator<String> it = closeSymbolStack.iterator(); it.hasNext();) {
				builder.append(it.next());
			}
		}
		//System.out.println("i is " + i);
	}
  1. 实现难度的比较app

从以上代码能够看出,递归实现的代码很是简洁,自然就是为生成json或xml这种格式的字符串设计的,而经过循环的方式遍历的代码显得比较烦琐,特别是为了实现生成json字符串的功能,使用了两个辅助变量closeSymbolStack和latestNode后显得更加烦琐,说实话为了使用循环的方式来生成json我花了大概一天的时间,而递归只有了几分钟而已。jvm

2. 性能比较性能

我分别对深度只有4的树形结构进行了几回循环测试,测试结果以下测试

循环次数 递归实现耗时(毫秒) 循环实时耗时(毫秒)
5000 40 70
10000 70 101
100000 306 394
1000000 1287 1638
10000000 10963 13621

而后又分别不一样的树的深度进行了测试,测试结果以下ui

树的深度 递归实现耗时(毫秒) 循环实时耗时(毫秒)
1000 2 5
2000 13 14
3000 7 14
4000 12 19
5000 java.lang.StackOverflowError 24
10000 java.lang.StackOverflowError 36
100000 java.lang.StackOverflowError 475

能够看出,若是树的深度不深的话,使用递归的性能会比使用循环的好一些,但若是树的深度比较深,树的深度超过5000后,使用递归的方式因为调用栈太深致使jvm抛出异常,而使用循环的方式依然正常。this

相关文章
相关标签/搜索