在实际开发中,有一种数据是类型,它存在父子关系,比如京东商城中,商品的分类有家用电器和服饰鞋帽,家用电器下边有大家电和家用电子,然后他们下边还有子类。而且这类父子关系有时深度是不确定的,本文用下面的方法,将所有类似分类的结点创建成一棵树并遍历打印他们。
1.结点要实现下面的接口:
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.工具类如下:
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.结点示例
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.测试:
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.结果:
[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