Java技术积累递归调用——解析树的基本实现原理

在做项目的过程中,经常会用到树结构。关于树结构的框架我也接触过几个,比如easyui中封装的树,Ztree等。当然这些封装好的框架只需要我们去按照API来使用即可,那么树的实现原理究竟是怎样的。今天用最原始的代码来拼接一下树的组成结构。

效果:

1、表结构

要想出现树结构,那么数据库中必须包含有可以形成树结构的表,也就是可以区分出父节点和子节点。

id:节点ID,pid;父节点id,level:等级标志(根节点为0,根的一级子节点为1,一次类推),name:节点名称

is_leaf:是否为叶子节点

2、根据树的结构进行拼接

在写这个方法前,首先要创建一个StringBuffer,用来讲这些html拼接成一个完整的字符串。

private StringBuffer sbTreeHTML=new StringBuffer();

 

 

[java] view plain copy
 
 print?
  1. /** 
  2.      * 递归读取分销商树 
  3.      *  
  4.      * 第四步,生成树结构 
  5.      * @param conn 
  6.      * @param id 
  7.      * @param level 控制层次 
  8.      */  
  9.     private void readClientTree(Connection conn,int id,int level)  
  10.     throws SQLException{  
  11.         String sql="select * from t_client where pid=?";  
  12.         PreparedStatement pstmt=null;  
  13.         ResultSet rs=null;  
  14.         try{  
  15.             pstmt=conn.prepareStatement(sql);  
  16.             pstmt.setInt(1, id);  
  17.             rs=pstmt.executeQuery();  
  18.             while(rs.next()){  
  19.                 sbTreeHTML.append("<div>");//每一个节点都作为一个div来出现  
  20.                 sbTreeHTML.append("\n");//另起一行  
  21.                 //遍历树结构的表,根据等级来决定每一个节点前加几个空白。出现缩进的效果。  
  22.                 for(int i=0;i<level;i++){  
  23.                     sbTreeHTML.append("<img src=\"../images/white.gif\">");//空白图片  
  24.                     sbTreeHTML.append("\n");  
  25.                 }  
  26.                 //在拼接的时候,要把每个节点的Id和名称读取出来,进行绑定,以便后续操作  
  27.                 if(Constants.No.equals(rs.getString("is_leaf"))){  
  28.                     //如果不是叶子节点的情况,节点前面为一个"+"的图片  
  29.                     sbTreeHTML.append("<img alt=\"展开\" style=\"cursor:hand;\" onClick=\"display('"+rs.getInt("id")+"');\" id=\"img"+rs.getInt("id")+"\" src=\"../images/plus.gif\">");  
  30.                     sbTreeHTML.append("\n");  
  31.                     //“+”图片后面跟着一个关闭标志的黄色小图片  
  32.                     sbTreeHTML.append("<img id=\"im"+rs.getInt("id")+"\" src=\"../images/closedfold.gif\">");  
  33.                     sbTreeHTML.append("\n");  
  34.                     sbTreeHTML.append("<a href=\"client_node_crud.jsp?id="+rs.getInt("id")+"\" target=\"clientDispAreaFrame\">"+rs.getString("name")+"</a>");  
  35.                     sbTreeHTML.append("\n");  
  36.                     sbTreeHTML.append("<div style=\"display:none;\" id=\"div" + rs.getInt("id") + "\">");  
  37.                     sbTreeHTML.append("\n");  
  38.                     //递归读取子节点  
  39.                     readClientTree(conn,rs.getInt("id"),level+1);  
  40.                     sbTreeHTML.append("</div>");  
  41.                     sbTreeHTML.append("\n");  
  42.                 }else{//叶子的情况  
  43.                     sbTreeHTML.append("<img src=\"../images/minus.gif\">");//减号  
  44.                     sbTreeHTML.append("\n");  
  45.                     sbTreeHTML.append("<img src=\"../images/openfold.gif\">");//张开图片  
  46.                     sbTreeHTML.append("\n");  
  47.                     if(Constants.YES.equals(rs.getString("is_client"))){  
  48.                         sbTreeHTML.append("<a href=\"client_crud.jsp?id="+rs.getInt("id")+"\" target=\"clientDispAreaFrame\">"+rs.getString("name")+"</a>");  
  49.                     }else{  
  50.                         sbTreeHTML.append("<a href=\"client_node_crud.jsp?id="+rs.getInt("id")+"\" target=\"clientDispAreaFrame\">"+rs.getString("name")+"</a>");  
  51.                     }  
  52.                       
  53.                 }  
  54.                 sbTreeHTML.append("\n");  
  55.                 sbTreeHTML.append("</div>");//每个div结束标识  
  56.                 sbTreeHTML.append("\n");  
  57.                   
  58.             }  
  59.         }finally{  
  60.             DbUtil.close(rs);  
  61.             DbUtil.close(pstmt);  
  62.         }  
  63.     }  


可根据注释来理解整个的拼接过程。

 

接下来,在树结构中,我们需要给他加点击事件,让节点响应点击事件来出现应有的树的结构的效果。在拼接的过程中响应的时间为display(id)

js:

 

[javascript] view plain copy
 
 print?
  1. function display(id) {  
  2.      eval("var div=div"+id);  
  3.      eval("var img=img"+id);  
  4.      eval("var im=im"+id);  
  5.      div.style.display=div.style.display=="block"?"none":"block";  
  6.      img.src=div.style.display=="block"?"../images/minus.gif":"../images/plus.gif";  
  7.      im.src=div.style.display=="block"?"../images/openfold.gif":"../images/closedfold.gif";  
  8.      img.alt=div.style.display=="block"?"展开":"关闭";  
  9. }  

 

 

通过以上描述,树结构基本上就已经成型了。剩下的就是在前台页面中调用此方法即可。

三、删除节点

接下来就是对树的操作了。

分析一下,增删改,只有删除是相对复杂的。它需要考虑的因素比较多,和查询类似,需要考虑是否为叶子节点,如果为非叶子节点,那么就需要进行递归删除它的子节点。还要考虑,删除的节点的父节点下面还有没有其他的子节点,如果没有需要更改父节点为叶子节点。

 

[java] view plain copy
 
 print?
  1. /** 
  2.      * 递归删除 
  3.      * @param conn 
  4.      */  
  5.     public void recursionDelNode(Connection conn,int id)  
  6.     throws SQLException{      
  7.         String sql="select * from t_client where pid=?";  
  8.         PreparedStatement pstmt=null;  
  9.         ResultSet rs=null;  
  10.         try{  
  11.             pstmt=conn.prepareStatement(sql);  
  12.             pstmt.setInt(1, id);  
  13.             rs=pstmt.executeQuery();  
  14.             while(rs.next()){  
  15.                 //判断如果为非叶子节点,进行递归查询  
  16.                 if(Constants.No.equals(rs.getString("is_leaf"))){  
  17.                     recursionDelNode(conn,rs.getInt("id"));  
  18.                 }  
  19.                 //执行删除操作  
  20.                 delNode(conn,rs.getInt("id"));  
  21.             }  
  22.             //删除自身节点  
  23.             delNode(conn,id);  
  24.         }catch(SQLException e){  
  25.             e.printStackTrace();  
  26.         }finally{  
  27.             DbUtil.close(rs);  
  28.             DbUtil.close(pstmt);  
  29.         }         
  30.     }  
  31.       
  32.       
  33.       
  34.       
  35.     /** 
  36.      * 删除节点 
  37.      * @param conn 
  38.      * @param id 
  39.      */  
  40.     public void delNode(Connection conn,int id)  
  41.     throws SQLException{  
  42.         String sql="delete from t_client where id=?";  
  43.         PreparedStatement pstmt=null;  
  44.         try{  
  45.               
  46.             pstmt=conn.prepareStatement(sql);  
  47.             pstmt.setInt(1, id);  
  48.             pstmt.executeUpdate();  
  49.               
  50.         }catch(SQLException e){  
  51.             e.printStackTrace();  
  52.         }finally{  
  53.             DbUtil.close(pstmt);  
  54.         }  
  55.     }  
  56.       

以上就是整个关于拼接树结构的核心部分了。树是Web端常用的界面效果,利用它在很多方面可以清晰的表达组织结构,给大家一目了然的效果,了解它的原理以应万变!

posted @ 2017-05-29 12:02  天涯海角路  阅读(372)  评论(0)    收藏  举报