根据数据的父子关系创建树形结构并实现遍历

  在实际开发中,有一种数据是类型,它存在父子关系,比如京东商城中,商品的分类有家用电器和服饰鞋帽,家用电器下边有大家电和家用电子,然后他们下边还有子类。而且这类父子关系有时深度是不确定的,本文用下面的方法,将所有类似分类的结点创建成一棵树并遍历打印他们。

1.结点要实现下面的接口:

 

  1. package subAndsup;  
  2. import java.util.List;  
  3.   
  4. /** 
  5.  * add by ak on 2013-11-28 
  6.  */  
  7. public  interface InheritedNode<T> {  
  8.   
  9. <SPAN style="WHITE-SPACE: pre"> </SPAN>boolean isChildFrom(T node);  
  10. <SPAN style="WHITE-SPACE: pre"> </SPAN>boolean isBrother(T node);  
  11. <SPAN style="WHITE-SPACE: pre"> </SPAN>void addChildNode(T node);  
  12. <SPAN style="WHITE-SPACE: pre"> </SPAN>List<T> getChildNodes();  
  13. <SPAN style="WHITE-SPACE: pre"> </SPAN>  
  14. }  
package subAndsup;
import java.util.List;

/**
 * add by ak on 2013-11-28
 */
public  interface InheritedNode<T> {

	boolean isChildFrom(T node);
	boolean isBrother(T node);
	void addChildNode(T node);
	List<T> getChildNodes();
 } 


2.工具类如下:

 

 

  1. package subAndsup;  
  2.   
  3. import java.util.ArrayDeque;  
  4. import java.util.ArrayList;  
  5. import java.util.Deque;  
  6. import java.util.Iterator;  
  7. import java.util.LinkedList;  
  8. import java.util.List;  
  9.   
  10. /** 
  11.  * add by ak on 2013-11-28 
  12.  */  
  13. public class TreeUtil {  
  14.       
  15.     /** 
  16.      * 将无序的结点集合,创建成一棵树。 
  17.      * 创建过程中使用了树的广度优先遍历,并且在考察无序集合的元素时, 
  18.      * 将其逐个插入到广度优先遍历结果集中,最后得到的结果集即是广度优先 
  19.      * 遍历的结果,也是从根元素(结果集中第一个元素)串联好的树形结构。 
  20.      * @param root 根元素 
  21.      * @param allCategory 无序的、不含根元素的集合 
  22.      * @return 包含子类的树形结构的根元素 
  23.      */  
  24.     public static <T extends InheritedNode> T getTree(T root, LinkedList<T> list) {  
  25.         // 模拟树的广度遍历结果的集合   
  26.         LinkedList<T> traversalList = new LinkedList<T>();  
  27.         traversalList.push(root);  
  28.         // 原始集合不为空,则继续迭代,将其中的元素加入到树的广度遍历结果集合中   
  29.         while(list.size() != 0) {  
  30.             // 迭代原始集合中的元素   
  31.             Iterator<T> iterAll = list.iterator();  
  32.             while(iterAll.hasNext()) {  
  33.                 T ndInAll = iterAll.next();  
  34.                 // 迭代树的广度遍历结果集合中的元素   
  35.                 Iterator<T> iterTrav = traversalList.iterator();  
  36.                 int indInTrav = 0;// 记录迭代当前元素的位置   
  37.                 boolean mate = false;// 标识是否找到父子类匹配关系   
  38.                 while(iterTrav.hasNext()) {  
  39.                     T ndInTrav = iterTrav.next();  
  40.                     // 如果存在父子类关系,则在在树的广度遍历结果集合中添加该元素,并父类中加入子元素   
  41.                     if(!mate) {  
  42.                         if(ndInAll.isChildFrom(ndInTrav)) {  
  43.                             // 如果存在父子类关系,则在父类中加入子元素,并设置标识   
  44.                             ndInTrav.addChildNode(ndInAll);  
  45.                             mate = true;  
  46.                         }  
  47.                     } else {  
  48.                         // 在找到iterInAll元素的父类之后,继续迭代,找到它的兄弟结点的位置   
  49.                         if(ndInAll.isBrother(ndInTrav)) {  
  50.                             break;  
  51.                         }  
  52.                     }  
  53.                     indInTrav++; // 执行++之后为迭代当前元素的位置   
  54.                 }  
  55.                 if(mate) {  
  56.                     // 如果找到iterInAll元素的父类,则在它的兄弟结点之前插入该元素   
  57.                     traversalList.add(indInTrav, ndInAll);  
  58.                     // 移除已经匹配的元素   
  59.                     iterAll.remove();  
  60.                 }  
  61.             }  
  62.         }  
  63.         // 最后将所有元素已经放到了树的广度遍历结果集合中,并且元素之间建立好了子父关系,即只取根就可得到所有元素   
  64.         T root2 = traversalList.getFirst();  
  65.         return root2;  
  66.     }  
  67.   
  68.     /** 
  69.      * 通过树的深度优先遍历获取树的遍历集合 
  70.      * @param root 树的根元素 
  71.      * @return 深度优先遍历方式的遍历集合 
  72.      */  
  73.     public static <T extends InheritedNode> List<T> createDepthFirstTraversalList(T root) {  
  74.         List<T> depthFirstTraversalList = new ArrayList<T>();  
  75.         // 深度优先遍历使用的栈结构   
  76.         Deque<T> stack = new ArrayDeque<T>();  
  77.         stack.addFirst(root);  
  78.         T node = null;  
  79.         while((node=stack.pollFirst()) != null) {  
  80.             List<T> sub = node.getChildNodes();  
  81.             if(sub != null && !sub.isEmpty()) {  
  82.                 for(int i=0; i<sub.size(); i++) {  
  83.                     stack.addFirst(sub.get(i));  
  84.                 }  
  85.             }  
  86.             depthFirstTraversalList.add(node);  
  87.         }  
  88.         return depthFirstTraversalList;  
  89.     }  
  90.       
  91.     /** 
  92.      * 通过树的广度优先遍历获取树的遍历集合 
  93.      * @param root 树的根元素 
  94.      * @return 深度优先遍历方式的遍历集合 
  95.      */  
  96.     public static <T extends InheritedNode> List<T> createBreadthFirstTraversalList(T root) {  
  97.         List<T> depthFirstTraversalList = new ArrayList<T>();  
  98.         // 广度优先遍历使用的队列结构   
  99.         Deque<T> stack = new ArrayDeque<T>();  
  100.         stack.addLast(root);  
  101.         T node = null;  
  102.         while((node=stack.pollFirst()) != null) {  
  103.             List<T> sub = node.getChildNodes();  
  104.             if(sub != null && !sub.isEmpty()) {  
  105.                 for(int i=0; i<sub.size(); i++) {  
  106.                     stack.addLast(sub.get(i));  
  107.                 }  
  108.             }  
  109.             depthFirstTraversalList.add(node);  
  110.         }  
  111.         return depthFirstTraversalList;  
  112.     }  
  113.       
  114.     /** 
  115.      * 打印树形结构,打印部分可以根据业务需求进行修改 
  116.      * @param root 树的根元素 
  117.      */  
  118.     public static <T extends InheritedNode> void printTreeByDepthFirstTraversal(T root) {  
  119.         List<T> depthFirstTraversalList = createDepthFirstTraversalList(root);  
  120.         System.out.println(depthFirstTraversalList<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif"></SPAN><SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">);</SPAN>  
  121.         // 记录每个元素的深度   
  122.         int[] deepList = new int[depthFirstTraversalList.size()];  
  123.         System.out.printf("%-5s", root);  
  124.         int deep = 1; // 考察的当前元素的深度   
  125.         deepList[0] = 1;  
  126.         for(int i=1; i<depthFirstTraversalList.size(); i++) {  
  127.             if(depthFirstTraversalList.get(i).isChildFrom(depthFirstTraversalList.get(i-1))) {  
  128.                 // 如果判断成立,则深度加1   
  129.                 deep++;  
  130.                 deepList[i] = deep;  
  131.                 // 如果上一个元素是当前元素的父亲,则打印   
  132.                 System.out.printf("%-5s", depthFirstTraversalList.get(i));  
  133.             } else {  
  134.                 // 如果上一个元素不是当前元素的父亲,则回溯迭代找到当前元素的父亲,换行进行打印   
  135.                 System.out.println();  
  136.                 for(int j=i-2; j>=0; j--) {  
  137.                     if(depthFirstTraversalList.get(i).isChildFrom(depthFirstTraversalList.get(j))) {  
  138.                         deep = deepList[j] + 1;  
  139.                         deepList[i] = deep;  
  140.                         // 当前元素之前用空进行打印,在此利用了元素的深度   
  141.                         for(int k=0; k<deep-1; k++) {  
  142.                             System.out.printf("%-5s", "");  
  143.                         }  
  144.                         System.out.printf("%-5s", depthFirstTraversalList.get(i));  
  145.                         break;  
  146.                     }  
  147.                 }  
  148.             }  
  149.         }  
  150.         System.out.println();  
  151.     }  
  152.       
  153. }  
package subAndsup;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * add by ak on 2013-11-28
 */
public class TreeUtil {
	
	/**
	 * 将无序的结点集合,创建成一棵树。
	 * 创建过程中使用了树的广度优先遍历,并且在考察无序集合的元素时,
	 * 将其逐个插入到广度优先遍历结果集中,最后得到的结果集即是广度优先
	 * 遍历的结果,也是从根元素(结果集中第一个元素)串联好的树形结构。
	 * @param root 根元素
	 * @param allCategory 无序的、不含根元素的集合
	 * @return 包含子类的树形结构的根元素
	 */
	public static <T extends InheritedNode> T getTree(T root, LinkedList<T> list) {
		// 模拟树的广度遍历结果的集合
		LinkedList<T> traversalList = new LinkedList<T>();
		traversalList.push(root);
		// 原始集合不为空,则继续迭代,将其中的元素加入到树的广度遍历结果集合中
		while(list.size() != 0) {
			// 迭代原始集合中的元素
			Iterator<T> iterAll = list.iterator();
			while(iterAll.hasNext()) {
				T ndInAll = iterAll.next();
				// 迭代树的广度遍历结果集合中的元素
				Iterator<T> iterTrav = traversalList.iterator();
				int indInTrav = 0;// 记录迭代当前元素的位置
				boolean mate = false;// 标识是否找到父子类匹配关系
				while(iterTrav.hasNext()) {
					T ndInTrav = iterTrav.next();
					// 如果存在父子类关系,则在在树的广度遍历结果集合中添加该元素,并父类中加入子元素
					if(!mate) {
						if(ndInAll.isChildFrom(ndInTrav)) {
							// 如果存在父子类关系,则在父类中加入子元素,并设置标识
							ndInTrav.addChildNode(ndInAll);
							mate = true;
						}
					} else {
						// 在找到iterInAll元素的父类之后,继续迭代,找到它的兄弟结点的位置
						if(ndInAll.isBrother(ndInTrav)) {
							break;
						}
					}
					indInTrav++; // 执行++之后为迭代当前元素的位置
				}
				if(mate) {
					// 如果找到iterInAll元素的父类,则在它的兄弟结点之前插入该元素
					traversalList.add(indInTrav, ndInAll);
					// 移除已经匹配的元素
					iterAll.remove();
				}
			}
		}
		// 最后将所有元素已经放到了树的广度遍历结果集合中,并且元素之间建立好了子父关系,即只取根就可得到所有元素
		T root2 = traversalList.getFirst();
		return root2;
	}

	/**
	 * 通过树的深度优先遍历获取树的遍历集合
	 * @param root 树的根元素
	 * @return 深度优先遍历方式的遍历集合
	 */
	public static <T extends InheritedNode> List<T> createDepthFirstTraversalList(T root) {
		List<T> depthFirstTraversalList = new ArrayList<T>();
		// 深度优先遍历使用的栈结构
		Deque<T> stack = new ArrayDeque<T>();
		stack.addFirst(root);
		T node = null;
		while((node=stack.pollFirst()) != null) {
			List<T> sub = node.getChildNodes();
			if(sub != null && !sub.isEmpty()) {
				for(int i=0; i<sub.size(); i++) {
					stack.addFirst(sub.get(i));
				}
			}
			depthFirstTraversalList.add(node);
		}
		return depthFirstTraversalList;
	}
	
	/**
	 * 通过树的广度优先遍历获取树的遍历集合
	 * @param root 树的根元素
	 * @return 深度优先遍历方式的遍历集合
	 */
	public static <T extends InheritedNode> List<T> createBreadthFirstTraversalList(T root) {
		List<T> depthFirstTraversalList = new ArrayList<T>();
		// 广度优先遍历使用的队列结构
		Deque<T> stack = new ArrayDeque<T>();
		stack.addLast(root);
		T node = null;
		while((node=stack.pollFirst()) != null) {
			List<T> sub = node.getChildNodes();
			if(sub != null && !sub.isEmpty()) {
				for(int i=0; i<sub.size(); i++) {
					stack.addLast(sub.get(i));
				}
			}
			depthFirstTraversalList.add(node);
		}
		return depthFirstTraversalList;
	}
	
	/**
	 * 打印树形结构,打印部分可以根据业务需求进行修改
	 * @param root 树的根元素
	 */
	public static <T extends InheritedNode> void printTreeByDepthFirstTraversal(T root) {
		List<T> depthFirstTraversalList = createDepthFirstTraversalList(root);
		System.out.println(depthFirstTraversalList);
		// 记录每个元素的深度
		int[] deepList = new int[depthFirstTraversalList.size()];
		System.out.printf("%-5s", root);
		int deep = 1; // 考察的当前元素的深度
		deepList[0] = 1;
		for(int i=1; i<depthFirstTraversalList.size(); i++) {
			if(depthFirstTraversalList.get(i).isChildFrom(depthFirstTraversalList.get(i-1))) {
				// 如果判断成立,则深度加1
				deep++;
				deepList[i] = deep;
				// 如果上一个元素是当前元素的父亲,则打印
				System.out.printf("%-5s", depthFirstTraversalList.get(i));
			} else {
				// 如果上一个元素不是当前元素的父亲,则回溯迭代找到当前元素的父亲,换行进行打印
				System.out.println();
				for(int j=i-2; j>=0; j--) {
					if(depthFirstTraversalList.get(i).isChildFrom(depthFirstTraversalList.get(j))) {
						deep = deepList[j] + 1;
						deepList[i] = deep;
						// 当前元素之前用空进行打印,在此利用了元素的深度
						for(int k=0; k<deep-1; k++) {
							System.out.printf("%-5s", "");
						}
						System.out.printf("%-5s", depthFirstTraversalList.get(i));
						break;
					}
				}
			}
		}
		System.out.println();
	}
	
}


3.结点示例

 

 

  1. package subAndsup;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class SimpleNode implements InheritedNode<SimpleNode> {  
  7.       
  8.     private String id;  
  9.     private String fid;  
  10.       
  11.     private List<SimpleNode> subSimpleNodeList;  
  12.       
  13.     public SimpleNode(String id, String fid) {  
  14.         this.id = id;  
  15.         this.fid = fid;  
  16.     }  
  17.       
  18.     public void addSubSimpleNode(SimpleNode subSimpleNode) {  
  19.     }  
  20.       
  21.     public String toString() {  
  22.         return id;  
  23.     }  
  24.   
  25.     @Override  
  26.     public void addChildNode(SimpleNode node) {  
  27.         if(subSimpleNodeList == null) {  
  28.             subSimpleNodeList = new ArrayList<SimpleNode>();  
  29.         }  
  30.         subSimpleNodeList.add(node);  
  31.     }  
  32.   
  33.     @Override  
  34.     public List<SimpleNode> getChildNodes() {  
  35.         return subSimpleNodeList;  
  36.     }  
  37.   
  38.     @Override  
  39.     public boolean isBrother(SimpleNode node) {  
  40.         return this.fid.equals(((SimpleNode)node).getFid());  
  41.     }  
  42.   
  43.     @Override  
  44.     public boolean isChildFrom(SimpleNode node) {  
  45.         return this.fid.equals(node.getId());  
  46.     }  
  47.   
  48.     public String getId() {  
  49.         return id;  
  50.     }  
  51.   
  52.     public void setId(String id) {  
  53.         this.id = id;  
  54.     }  
  55.   
  56.     public String getFid() {  
  57.         return fid;  
  58.     }  
  59.   
  60.     public void setFid(String fid) {  
  61.         this.fid = fid;  
  62.     }  
  63.   
  64. }  
package subAndsup;

import java.util.ArrayList;
import java.util.List;

public class SimpleNode implements InheritedNode<SimpleNode> {
	
	private String id;
	private String fid;
	
	private List<SimpleNode> subSimpleNodeList;
	
	public SimpleNode(String id, String fid) {
		this.id = id;
		this.fid = fid;
	}
	
	public void addSubSimpleNode(SimpleNode subSimpleNode) {
	}
	
	public String toString() {
		return id;
	}

	@Override
	public void addChildNode(SimpleNode node) {
		if(subSimpleNodeList == null) {
			subSimpleNodeList = new ArrayList<SimpleNode>();
		}
		subSimpleNodeList.add(node);
	}

	@Override
	public List<SimpleNode> getChildNodes() {
		return subSimpleNodeList;
	}

	@Override
	public boolean isBrother(SimpleNode node) {
		return this.fid.equals(((SimpleNode)node).getFid());
	}

	@Override
	public boolean isChildFrom(SimpleNode node) {
		return this.fid.equals(node.getId());
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getFid() {
		return fid;
	}

	public void setFid(String fid) {
		this.fid = fid;
	}

}


4.测试:

 

 

  1. package subAndsup;  
  2.   
  3. import java.util.LinkedList;  
  4.   
  5. public class Test {  
  6.   
  7.     /** 
  8.      * @param args 
  9.      */  
  10.     public static void main(String[] args) {  
  11.         LinkedList<SimpleNode> list = new LinkedList<SimpleNode>();  
  12.         list.add(new SimpleNode("B2", "B"));  
  13.         list.add(new SimpleNode("D", "A"));  
  14.         list.add(new SimpleNode("C2", "C"));  
  15.         list.add(new SimpleNode("C12", "C1"));  
  16.         list.add(new SimpleNode("D11", "D1"));  
  17.         list.add(new SimpleNode("B1", "B"));  
  18.         list.add(new SimpleNode("B11", "B1"));  
  19.         list.add(new SimpleNode("B12", "B1"));  
  20.         list.add(new SimpleNode("C11", "C1"));  
  21.         list.add(new SimpleNode("B22", "B2"));  
  22.         list.add(new SimpleNode("C1", "C"));  
  23.         list.add(new SimpleNode("B", "A"));  
  24.         list.add(new SimpleNode("D1", "D"));  
  25.         list.add(new SimpleNode("C", "A"));  
  26.           
  27.         SimpleNode root = new SimpleNode("A", null);  
  28.         root = TreeUtil.getTree(root, list);  
  29.           
  30.         TreeUtil.printTreeByDepthFirstTraversal(root);  
  31.           
  32.     }  
  33.   
  34. }  
package subAndsup;

import java.util.LinkedList;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		LinkedList<SimpleNode> list = new LinkedList<SimpleNode>();
		list.add(new SimpleNode("B2", "B"));
		list.add(new SimpleNode("D", "A"));
		list.add(new SimpleNode("C2", "C"));
		list.add(new SimpleNode("C12", "C1"));
		list.add(new SimpleNode("D11", "D1"));
		list.add(new SimpleNode("B1", "B"));
		list.add(new SimpleNode("B11", "B1"));
		list.add(new SimpleNode("B12", "B1"));
		list.add(new SimpleNode("C11", "C1"));
		list.add(new SimpleNode("B22", "B2"));
		list.add(new SimpleNode("C1", "C"));
		list.add(new SimpleNode("B", "A"));
		list.add(new SimpleNode("D1", "D"));
		list.add(new SimpleNode("C", "A"));
		
		SimpleNode root = new SimpleNode("A", null);
		root = TreeUtil.getTree(root, list);
		
		TreeUtil.printTreeByDepthFirstTraversal(root);
		
	}

}


5.结果:

 

 

  1. [A, C, C1, C11, C12, C2, B, B1, B12, B11, B2, B22, D, D1, D11]  
  2. A    C    C1   C11    
  3.                C12    
  4.           C2     
  5.      B    B1   B12    
  6.                B11    
  7.           B2   B22    
  8.      D    D1   D11    
[A, C, C1, C11, C12, C2, B, B1, B12, B11, B2, B22, D, D1, D11]
A    C    C1   C11  
               C12  
          C2   
     B    B1   B12  
               B11  
          B2   B22  
     D    D1   D11  



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值