用Java实现多叉树型结构数据生成

    项目中需要做一个地区选择插件,由于地区之间的关系为树形结构,所以我们可以用多叉树来存储地区数据,并将多叉树转为json字符串前台做处理。

    首先,在实现代码介绍之前我们需要了解,什么是树以及树的结构。

    以下摘选自百度百科

    树(tree)是包含nn>=0)个结点的有穷集,其中:

1)每个元素称为结点(node);

2)有一个特定的结点被称为根结点或树根(root)。

3)除根结点之外的其余数据元素被分为mm≥0)个互不相交的集合T1T2……Tm-1,其中每一个集合Ti1<=i<=m)本身也是一棵树,被称作原树的子树(subtree)。

    树也可以这样定义:树是由根结点和若干颗子树构成的。树是由一个集合以及在该集合上定义的一种关系构成的。集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构。在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树的根结点,或称为树根。

    树结构图形如下

                                          

 

    多叉树也多被叫为b树

    在了解了树的结构之后,我们就可以根据树的基本模型来进行java代码的实现。

    不管是root节点还是叶子节点,都包含着基本的结构,节点数据、父节点、当前节点及子节点指针。由各个节点通过子节点指针关联起来就形成的一颗b树。那么我们就先定义对象来存储节点。

 

public class Node {

       //节点id

    public String id;

       //父节点id

    public String pid;

       //节点数据

    public String content;

 

//子节点指针集合

List<Node> nodes=null;

}

创建一个树结构对象,存储数据

public class Tree {

    private Node node=null;

    private List<Map> datas=null;

}

而完成一个树型结构,最主要的步骤:

第一步,构建父节点

 

   //搜索父节点

        Map t=FindDatasById(id);

        //初始化父节点

        this.node=new Node(t);

第二步,根据根节点数据,搜索对应子节点插入到父节点中。

//递归初始化节点数据

init(this.node);

//初始化树

    private void init(Node node){

            for(Map temp:FindListDatasByPId(node.getId())){//搜索子节点数据

                Node tempNode=new Node(temp);

                init(tempNode); //初始化子节点

                node.nodes.add(tempNode); //将子节点加入当前父节点

        }

}

实现逻辑:

  1. 找到当前节点下的所有子节点。
  2. 对子节点循环,将所有子节点初始化。
  3. 将已初始化的子节点加入当前节点。

基本一个b树的数据就被保存到咱们的Tree对象中了

而在项目用到的时候需要用该树做一个下拉选地区的一个功能,那么我们还需要将该树生成为json格式的数据,代码如下:

  private static String NODE_ID="id";

  private static String NODE_PID="pid";

  private static String NODE_NAME="name";

initJsonStr(this.node);

public void initJsonStr(Node node){

        Node tempNode=node;

        if(node.getId()!=node.getId()){

            jsonStr.append(",");

        }

        jsonStr.append("{").

                append("\""+NODE_ID+"\":\"").append(tempNode.getId()).append("\",").

        append("\""+NODE_NAME+"\":\"").append(tempNode.getContent()).append("\",").

        append("\""+NODE_PID+"\":\"").append(tempNode.getPid()).append("\"");

        if(isHaveLeafWithPid(tempNode)){

            jsonStr.append(",\"nodes\":[");

            List<Node> tempnodes=tempNode.nodes;

            for(int i=0;i<tempnodes.size();i++) {

                initJsonStr(tempnodes.get(i));

                if(tempnodes.size()-1!=i){

                    jsonStr.append(",");

                }

            }

            jsonStr.append("]");

        }

        jsonStr.append("}");

}

跟构建树的过程相类似,也是使用了递归的操作,请参照树节点构造步骤。

       数据量大时’符号可能会让json字符无法被识别,所以这里采用”来构建json对象属性键值对。

       数据库中,表结构数据至少包含为 id,pid,name。

       下面贴出完整代码

//Node

package com.fenghao.sys.pojo;

import
java.util.ArrayList;
import
java.util.List;
import
java.util.Map;

public class
Node {

   
public String id;

    public
String pid;

    public
String content;

   
List<Node> nodes=null;
    public
Node(){
       
this.nodes=new ArrayList<>();
   
}
  
public Node(String id,String pid,String content){
       
this.id=id;
        this
.pid=pid;
        this
.content=content;
       if
(nodes==null){
          
nodes=new ArrayList<>();
      
}
    }
   
public Node(Map map){
        System.
out.println(map);
       
id=(String) map.get("id");
       
pid=(String) map.get("pid");
       
content=(String) map.get("name");
        if
(nodes==null){
           
nodes=new ArrayList<>();
       
}
    }
   
public String getId() {
       
return id;
   
}

   
public void setId(String id) {
       
this.id = id;
   
}

   
public String getPid() {
       
return pid;
   
}

   
public void setPid(String pid) {
       
this.pid = pid;
   
}

   
public String getContent() {
        
return content;
   
}

   
public void setContent(String content) {
       
this.content = content;
   
}
   
public void setNode(Node node){
      
this.nodes.add(node);
   
}
   
public List<Node> getNodes(){
      
return this.nodes;
   
}
}

//Tree

package com.fenghao.sys.pojo;



import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;



public class Tree {

    private Node node=null;

    private List<Map> datas=null;

    private StringBuffer jsonStr=new StringBuffer();

    private static String NODE_ID="id";

    private static String NODE_PID="pid";

    private static String NODE_NAME="name";

    private Tree(List<Map> datas){

        this.datas=datas;

    }

    public static  Tree getInstance(List<Map> datas,String id){

       Tree temp= new Tree(datas);

       try {

           temp.init(id);

           return temp;

       }catch (Exception e){

           e.printStackTrace();

       }

      return null;

    }

    public String getJSONString(){

        return jsonStr.toString();

    }

    //初始化单树父节点

    private void init(String id) throws Exception{

        //搜索父节点

        Map t=FindDatasById(id);

        if(null==t){//假如搜索的父节点id数据不存在,抛出异常

            throw new Exception();

        }

        //初始化父节点

        this.node=new Node(t);

        init(this.node);

        initJsonStr(this.node);

    }

    //初始化树

    private void init(Node node){

        String id=node.getId();

            for(Map temp:FindListDatasByPId(id)){

                //假如遇到节点id为空或者节点数据为空的,跳过本次循环

                if(isEmpty(temp.get(NODE_ID))||isEmpty(temp.get(NODE_NAME))){

                    continue;

                }

                Node tempNode=new Node(temp);

                init(tempNode); //初始化子节点

                node.nodes.add(tempNode); //将子节点加入当前父节点

        }

    }

    public void initJsonStr(Node node){

        Node tempNode=node;

        if(node.getId()!=node.getId()){

            jsonStr.append(",");

        }

        jsonStr.append("{").

                append("\""+NODE_ID+"\":\"").append(tempNode.getId()).append("\",").

        append("\""+NODE_NAME+"\":\"").append(tempNode.getContent()).append("\",").

        append("\""+NODE_PID+"\":\"").append(tempNode.getPid()).append("\"");

        if(isHaveLeafWithPid(tempNode)){

            jsonStr.append(",\"nodes\":[");

            List<Node> tempnodes=tempNode.nodes;

            for(int i=0;i<tempnodes.size();i++) {

                initJsonStr(tempnodes.get(i));

                if(tempnodes.size()-1!=i){

                    jsonStr.append(",");

                }

            }

            jsonStr.append("]");

        }

        jsonStr.append("}");

    }

    //判断父节点下是否有子节点

    public boolean isHaveLeafWithPid(String pid){

        for(int i=0;i<this.datas.size();i++){

            Map temp=this.datas.get(i);

            if(temp.get(NODE_PID)!=null&&temp.get(NODE_PID).toString().equals(pid)){

               return true;

            }

        }

        return false;

    }

    //判断父节点下是否有子节点

    public boolean isHaveLeafWithPid(Node node){

      if(node.nodes!=null&&node.nodes.size()>0){

          return true;

      }

        return false;

    }

    //找到父节点下的所有子节点

    private List<Map> FindListDatasByPId(String pid){

        List<Map> map=new ArrayList<>();

        for(int i=this.datas.size()-1;i>=0;i--){

            Map temp=this.datas.get(i);

            if(temp.get(NODE_PID)!=null&&temp.get(NODE_PID).toString().equals(pid)){

                this.datas.remove(i);

               map.add(temp);

            }

        }

        return map;

    }

    //找到父节点

    private Map FindDatasById(String id){

        for(int i=0;i<this.datas.size();i++){

         Map temp= this.datas.get(i);

         if(temp.get(NODE_ID).toString().equals(id)){

             this.datas.remove(i);

             return temp;

         }

        }

        return null;

    }

    private boolean isEmpty(Object obj){

        if(null==obj||"".equals(obj)){

            return true;

        }

        return false;

    }

}

//test.java

package test;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.slf4j.LoggerFactory;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import  org.slf4j.Logger;

import java.util.*;

import org.springframework.beans.factory.annotation.Autowired;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration({"classpath:spring-datasource.xml","classpath:spring-mybatis.xml"})

public class Testmybatis {

    @Autowired

    SqlSessionFactory sqlSessionFactory;

    public Logger logger=LoggerFactory.getLogger(this.getClass());

 

    @Test

    public void test2(){

        SqlSession session = sqlSessionFactory.openSession();

      List<Map> result=  session.selectList("area.selectArea");

       Tree temp=Tree.getInstance(result,"370000");

        logger.info(temp.getJSONString());

    }

}

粘贴部分数据

{name=潍坊市, pid=370000, id=370700}

{name=昌邑市, pid=370700, id=370786}

{name=高密市, pid=370700, id=370785}

{name=安丘市, pid=370700, id=370784}

{name=寿光市, pid=370700, id=370783}

 

//sql

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="area">

 <select id="selectArea" resultType="Map" parameterType="java.lang.String">
      select DISTINCT id, pid,name from   table
    </select>

</mapper>
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值