zoukankan      html  css  js  c++  java
  • 根据数据的父子关系创建树形结构并实现遍历

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

    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  
    



  • 相关阅读:
    设计模式系列
    Python3 系列之 可变参数和关键字参数
    设计模式系列
    【HANA系列】SAP HANA ODBC error due to mismatch of version
    【FICO系列】SAP FICO FS00修改科目为未清项目管理
    【FIORI系列】SAP OpenUI5 (SAPUI5) js框架简单介绍
    【HANA系列】SAP HANA SQL获取当前日期加若干天后的日期
    【HANA系列】SAP HANA SQL获取本周的周一
    【HANA系列】SAP HANA SQL获取当前日期
    【HANA系列】SAP HANA SQL获取当前日期最后一天
  • 原文地址:https://www.cnblogs.com/firstdream/p/5240828.html
Copyright © 2011-2022 走看看