第七篇:递归插入,修改版

项目场景:
        将一个树上的节点插入到数据库,节点之间有父子关系,每个节点有一个id和pId,父子关系表述为:父节点的id为子节点的pId值。在上一个日志中,所有节点的值已经全部打包完传给了后台。现在执行插入操作。
难点:
        举个例,A是根节点,他有一个treeid,姑且叫Aid,他的父id为null。插入数据库后会生成一个新的id,姑且叫NewAid,
以Aid作为父id的有五个儿子BCDEF,将继续插入数据库,此时他们以新生成的NewAid作为pid这个字段值插入数据库,生成了新的Bid,Cid,Did,Eid,Fid.依此类推BCDEF下面有B1,B2;C1,C2,C3;D1,D2,D3,D4>>>>>>>继续插入
 
        分析一下,其实就是说在前端时,每个节点都有个treeid和pid,传到后台是为了找他们的子节点,
当每个节点生成了新的id后,就将这个id作为子节点的pid继续插入子节点,又生成一批新的id作为子节点的子节点的pid

        所以,难点就是递归怎么写,因为我以前遇到的少,所以卡壳了一天才完成,fastJson上篇已经说明

直接上代码说明,无关代码可忽略

public void insertCatalog(){
    HttpServletRequest req = ServletActionContext.getRequest();
    String datalist = req.getParameter("datalist");
    JSONArray ja  = JSON.parseArray(datalist);//解析传过来的json串 
    JSONObject rootJO = ja.getJSONObject(0);//入口ja的第一个对象约定是根节点,先插入
    String newid = add2DB(rootJO);//插入后返回id 
    String oldid = rootJO.getString("id");//这是前台传过来的id 
    ja.remove(0);//插入一条就移走一条,减少后面递归的量 
    insert(ja, newid,oldid);//递归插入的入口
}
//递归插入
public void insert(JSONArray ja,String newid,String oldid) {
    if (newid==null || "".equals(newid) ) return;         //如果返回的newid不对劲,终止 
    if (ja.isEmpty())  return;                                       //递归插入的出口
    for (int i=0; i<ja.size(); i++) {
        JSONObject jo = ja.getJSONObject(i);
        if ( oldid.equals( jo.get("pId") ) ) {              //根据每个节点的id寻找他的儿子们
        jo.remove("parentID");                              //如果找到了,换掉parentID这个属性的值
        jo.put("parentID", newid);                          //给他赋的值就是每次生成的newid
        String newCreateId = add2DB(jo);             //插入,返回新的id
        String currentId = jo.getString("id");            //这是当前被插入的节点的id,作为下次寻找儿子们用
        ja.remove(i);                                               //这里每插入一条,移除 
        insert(ja, newCreateId,currentId);             //递归方法 
      }
  }
}

 
add2DB这个方法就不记录了,就是茶如数据库,返回插入后的新id的方法 


到此,这个递归就完成了,测试插入成功,写完了还是觉得意犹未尽~~~~~~~~~~~~~~~~~~~~~~~~~
**********************************************************************************************************************************************
以上递归方法测试,会跳过偶数下标的数据,现在没有找到问题出在哪儿,最大的可能是,for循环内部又使用了递归方法
查阅过相关技术大牛的文章,有人对for循环内部再递归的情形做过研究,我自己觉得这样设计(有时候不得不)对程序逻辑流需要一定的
想象力。再者需要了解一个东西。递归只会往深处调用,不存在什么跳出for循环外调用自己。

首先,java的堆存对象,栈存基本数据类型和对象引用地址这个是基本的,也就是说,每一次递归方法调用都会重新产生很多变量值,如果再加上for循环,那么栈里面的变量增加会很快,栈中的变量一般只会在程序结束的时候才会被清空,所以当循环很多,或者递归很深的时候,jvm的栈可能会被塞爆。这个仅做一个了解。

我要说的是,递归的时候,不用担心递归之前的变量被覆盖或清空了,因为每次调用方法,栈都会重新给这个方法(要产生变量)分配属于该方法的内存,也就是分配一块儿地方,所以递归只会往更深的方向执行方法,打个比方,A方法在内部递归调用自己,好比A克隆了A1,递归的时候调的A1,然后继续克隆继续调用,体现在栈里面就是不断分配空间给这些A1,A2,A3、、、、、、

这个递归的方法我改了一下,

public void insert(JSONArray ja,String newid,String oldid) {
  if (newid==null||"".equals(newid)) return;
  //递归插入的出口
  if(ja.isEmpty())return;
  List<JSONObject> joList = search(ja,oldid);//先搜索儿子们,存到joList 中
  ja.removeAll(joList);//搜索完了全部移除
  for(int i=0;i<joList.size();i++){
    JSONObject jo = joList.get(i);
    jo.remove("parentID");
    jo.put("parentID", newid);
    String newCreateId = add2DB(jo);
    String currentId = jo.getString("id");
    insert(ja,newCreateId,currentId);
  }
}
新加的搜索的方法

public List<JSONObject> search(JSONArray ja,String id){
  if(ja.isEmpty())return null;
  List<JSONObject> joList = new ArrayList<JSONObject>();
  for(int i=0;i<ja.size();i++){
    JSONObject jo = ja.getJSONObject(i);
    if(id.equals(jo.get("pId"))){
    joList.add(jo);
    }
  }
  return joList;
} 
整体思路是:首先最开始的时候插入根节点产生id,根节点移除
然后由根节点原来的id在数据包ja里,调search方法返回他的所有子节点装进list,根节点的子节点们移除
遍历list循环插入,每插入一条产生新id,再调用搜索方法搜索他的儿子们,移除,插入,依次往深处递归执行
直到“第一条”的id下的所有儿子们全部插入完成,开始插入“第二条”
第二条的模式和第一条一样,也是插入,产生id,找儿子,插入儿子,儿子找孙子继续插入
直到第一批的节点全部插入完成,所有节点就全部插入完成

猜你喜欢

转载自www.cnblogs.com/yb38156/p/9821861.html