1)链表List中元素为Element:
a, 每个元素有一个自己的orgId;
b 指向父亲的parentOrgId;
c,孩子链表 chilren,链表中为空
详细的数据成员见文末的类Element
2) 目的: 将List中存在父节点的节点 放到它节点的孩子链表chilren中
3)收获或注意点:
a) 在list中 用foreach循环时很难在当前list中做增删,一个好的方法是使用迭代器;
b) java中非原始类型的数据 在参数传递时是引用,而非副本拷贝,所以可以在子函数中修改数据
c) 性能提升
方法1: 重复循环遍历链表List,将元素加入到它的父亲下,并在List中删除。
初始状态:第一层包含List中所有元素
结束条件:链表List中节点不再变化
时间复杂度:o( n~2) 且有递归
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//将一层排列的List 转换为具有多层树形结构的List
public class TreeFromList {
TreeFromList(){
}
Boolean changeList( List<Element> elist, Element element ){
if(elist == null) return false;
for( Element temp : elist){
//如果元素父节点指向自己,会把自己删除
//这句很重要
if(temp.equals(element)) continue;
if(element.getParentOrgId() == temp.getOrgId()){
if(temp.getChildren()!=null){
temp.getChildren().add(element);
}
else {
List<Element> children = new ArrayList<Element>();
children.add(element);
temp.setChildren(children);
}
return true;
}
else if(temp.getChildren()!=null){
//在该节点的孩子节点中查找
Boolean bool=changeList(temp.getChildren(), element);
if(bool) return true;
}
}
return false;
}
public List<Element> convertList( List<Element> elist){
if(elist == null) return null;
int oldlength = elist.size();
int newlength = oldlength-1;
while( oldlength > newlength )
{
oldlength = newlength;
Iterator<Element> it = elist.iterator();
while(it.hasNext()){
Element temp = it.next();
Boolean bool=changeList( elist, temp);
if(bool){
System.out.println("temp =" + String.valueOf(temp.getOrgId()));
it.remove();
}
}
newlength = elist.size();
}
return elist;
}
void print(List<Element> elist ){
for(Element e:elist){
System.out.println("id="+String.valueOf(e.getOrgId())+ "; parentID="+String.valueOf(e.getParentOrgId()) );
if(e.getChildren()!= null) {
print(e.getChildren());
}
}
}
public static void main(String[] args){
TreeFromList tree = new TreeFromList();
List<Element> elist = new ArrayList<Element>();
Element e1= new Element(0,0) ; elist.add(e1);
Element e2= new Element(1,0) ; elist.add(e2);
Element e3= new Element(2,1) ; elist.add(e3);
Element e4= new Element(3,2) ; elist.add(e4);
Element e5= new Element(4,2) ; elist.add(e5);
Element e6= new Element(5,1) ; elist.add(e6);
Element e7= new Element(6,2) ; elist.add(e7);
Element e8= new Element(7,3) ; elist.add(e8);
Element e9= new Element(8,1) ; elist.add(e9);
Element e10= new Element(9,0) ; elist.add(e10);
elist = tree.convertList(elist);
System.out.println("length =" + elist.size());
tree.print(elist);
}
}
方法2: 在有用户交互的情况下,用户点击一个节点会在后台数据库中显示该节点的所有孩子节点
初始状态:数据放在数据库表中
获取条件:用户点击,多次查询,
优势:没用缓存,速度快
不足: 查询后台数据库较多
//直接在数据库中找孩子
//方法3: 指定顶层节点为 父亲节点,每次都查表,从上往下生成树
public List<Element> getOrgChildrenByOrgId( Context ctx) throws Exception{
List<Element> orgListRoot=null;
//数据库中获取顶层节点
orgListRoot = orgService.getOrgRoot();
//根据第一层获取第二层节点
orgListRoot=getOrgChildren( orgListRoot);
return orgListRoot;
}
//获取一个链表的孩子节点
private List<Element> getOrgChildren( List<Element> orgListRoot) throws Exception{
for(Element tempBean: orgListRoot){
if(tempBean.getOrgId()==null) continue;
//在数据库中获取节点的孩子
children= orgService.getOrgChildrenByOrgId(tempBean.getOrgId());
if(children !=null && children.isEmpty()== false){
tempBean.setChildren(children);
}
}
return orgListRoot;
}
方法3: 重要思想,通过Map能够很快找到对应的元素
a ,一次性读取整个链表List,并且按照parentid排序(在非读数据库情况下可以使用快排排序)得到orderList,时间复杂度为o(nlogn)
b,根据orderList,将具有相同parentid的元素放到同一个map中得到 Map<parentid,map>, 其中子map为map<id,null>,
并使用一个类型为Map<id,elment>的mapQuery 保存所有的elment,使得根据id查询elment的查询为o(1)
总的时间复杂度为o(n)
c,在数据库中或者orderList中可以得到 顶层节点链表rootList
d,采用广度优先遍历或者深度优先遍历rootList中元素,根据parentid在Map<parentid,map>中一次直接查询到节点的所有孩子,并不断迭代
即可得到在o(n)时间复杂度内构成树
List<Element> orgCSList= new ArrayList<Element>();
public List<Element> getOrgByCollectStye(Context ctx) throws Exception{
//找顶层节点
List<Element> orgListRoot = orgService.getOrgRoot();
//顶层节点保存到orgList
for(Element ob:orgListRoot){
orgCSList.add(ob);
mapQuery.put(ob.getOrgId(), ob);
}
//找到根据父节点排序好的所有节点链表
List<Element> tempOrderOrgList = orgService.getOrderOrg();
//将具有相同父ID的节点放到一个map(pid, map(id,Element))
Map<String, Object> tempOrderOrgMap = convertGroup(tempOrderOrgList);
//生成Map树 (mapTree)和 orgList
collectToMapTree(tempOrderOrgMap, orgCSList);
return orgCSList;
}
//第二项在第一项中收集
private void collectToMapTree( Map<String, Object> tempOrderOrgMap,
List<Element> orgList) throws Exception{
for (Element ob:orgList ){
List<Element> children = new ArrayList<Element>();
Map<String,Element> obMap = (Map<String, Element>)tempOrderOrgMap.get( ob.getOrgId() );
//没有孩子
if(obMap ==null || obMap.isEmpty()) {
continue;
}
else {
for(Map.Entry<String, Element> mapBean: obMap.entrySet()){
children.add(mapBean.getValue());
}
collectToMapTree(tempOrderOrgMap, children);
ob.setChildren(children);
}
}
}
Map<String, Object > convertGroup(List<Element> orgList) {
if(orgList==null || orgList.isEmpty()) return null;
Map<String, Object > tempMap= new HashMap<String, Object >();
String pid =" ";
Map<String, Element > newMap=null;
for(Element ob:orgList){
//在顶层Map中就不加入
if(mapQuery.containsKey(ob.getOrgId()) )
continue;
//如果当前节点的pid与此前节点的pid不同,则是新的子Map
//相等则加入前面的子map中
if(pid.equalsIgnoreCase(ob.getParentOrgId() ) == false ) {
//找到新的子Map,如果旧的子Map不为空,则保存
if(newMap != null) tempMap.put(pid, newMap);
newMap = new HashMap<String,Element>();
newMap.put(ob.getOrgId(), ob);
pid = ob.getParentOrgId();
}
else{//相等则有相同的父ID
newMap.put(ob.getOrgId(), ob);
}
}
return tempMap;
}
元素类
import java.util.List;
public class Element {
private Integer orgId;
private Integer parentOrgId;
private List<Element> children = null;
Element(Integer orgId, Integer parentOrgId){
this.orgId= orgId;
this.parentOrgId = parentOrgId;
}
public void setOrgId(Integer orgId){
this.orgId =orgId;
}
public Integer getOrgId(){
return orgId;
}
public void setParentOrgId(Integer parentOrgId){
this.parentOrgId =parentOrgId;
}
public Integer getParentOrgId(){
return parentOrgId;
}
public void setChildren(List<Element> children){
this.children =children;
}
public List<Element> getChildren(){
return children;
}
}