Java实现通过递归遍历树形结构

树形结构在数据库的设计过程中是一种比较常见的模型,指的是各元素之间存在‘一对多’的结构模型。在树形结构中,树根结点没有前驱结点,其余每个结点有且只有一个前驱结点。叶子结点没有后续结点,其余每个结点的后续节点数可以是一个也可以是多个。
在实际应用中,树形结构可以用来抽象很多具体问题,比如在‘成绩管理系统’中,班级类的表示,在该类的表示中,最上层应为‘XX学校’,下面依次是‘年级’、‘班级’。这便是一个典型的树形结构模型,最上层的‘XX学校’是树根节点,最下层的‘班级’则为叶子节点。
在设计数据库时,可为班级表设置四个字段:
‘classes_id’:表示对于树形结构中节点的编号;
‘classes_name’:表示节点名称;
‘pid’:表示当前节点父节点的id;
‘leaf’:用于区分当前节点是否为叶子节点。


各字段取值示例


在数据库中建好对应的表’t_classes’后,可以使用Java实现对该表的CRUD操作,下面介绍递归的方法实现对表中元素遍历查询,并将其有层次地显示出来。


对应的Java语句如下所示:

package com.njupt.exam.manager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.njupt.exam.util.DbUtil;

/**
 * 班级管理类
 * @author hzy
 *
 */

public class ClassesManager {

    public void dispalyClassesList() {
        Connection conn = null;
        try {
            conn = DbUtil.getConnection();
            displayClassesList(conn,0,0);
        } catch(Exception e) {
            e.printStackTrace();

//此处conn遵循一个原则:在哪里打开就在哪里关闭

        } finally {
            DbUtil.close(conn);
        }
    }

//构成方法重载

    public void displayClassList(Connection conn,int pid,int level) {

//level表示空格的个数,随节点层数的增加而增加,使显示结果具有层次感

//此处s用于使显示结果更具有层次感

        String s = "";
        PreparedStatement psta = null;
        ResultSet rs = null;
        String sql = "use 成绩管理系统 select * from t_class where pid = ?";
        for(int i=0;i<level;i++)
            s += "  ";
        try {
            psta = conn.prepareStatement(sql);
            psta.setInt(1,pid);
            rs = psta.executeQuery();
            while(rs.next()) {

//打印输出当前节点的信息,当前节点的父节点为参数pid

                System.out.println(s + rs.getInt("class_id") + "  " + rs.getString("class_name"));

//判断当前节点是否为叶子节点

/*如果不是叶子节点,说明当前节点下还有子节点,需要再次调用自身对子节点进行显示,此时displayClassesList函数中应当传入的参数为conn,由于要对子节点进行显示,故pid应为当前节点的id,level随着节点层数的变化变为level+1*/

                if(rs.getInt("leaf") == 0) {                                                                          displayClassesList(conn,rs.getInt("class_id"),level+1)
                }  
            }
        } catch(SQLException e1) {
            e1.printStackTrace();
        } finally {
            DbUtil.close(rs);
            DbUtil.close(psta);
        }                               
    }

//主函数实现对显示函数的调用

    public static void main(String args[]) {
        new ClassesManager.displayClassesList();
    }
} 

执行结果为:

程序执行结果


/** * 根据等级查询类目树 * * @param level * @return */ @Override public List queryCategoryTree(Integer level) { //查询当前级别下类目 List list = categoryDAO.list(level); //组装好的类目树,返回前端 List categoryTree = new ArrayList(); //所有类目 List allDTOList = new ArrayList(); if (CollectionUtils.isEmpty(list)) { return categoryTree; } for (CategoryDO categoryDO : list) { allDTOList.add(new CategoryTreeDTO().convertDOToDTO(categoryDO)); } //当前等级类目 categoryTree = allDTOList.stream().filter(dto -> level.equals(dto.getLevel())).collect(Collectors.toList()); for (CategoryTreeDTO categoryTreeDTO : categoryTree) { //组装类目为树结构 assembleTree(categoryTreeDTO, allDTOList,Constants.CATEGORY_MAX_LEVEL - level); } return categoryTree; } /** * 组装树 * * @param categoryTreeDTO * @param allList * @param remainRecursionCount 剩余递归次数 * @return */ public CategoryTreeDTO assembleTree(CategoryTreeDTO categoryTreeDTO, List allList, int remainRecursionCount) { remainRecursionCount--; //最大递归次数不超过Constants.CATEGORY_MAX_LEVEL-level次,防止坏数据死循环 if(remainRecursionCount < 0){ return categoryTreeDTO; } String categoryCode = categoryTreeDTO.getCategoryCode(); Integer level = categoryTreeDTO.getLevel(); //到达最后等级树返回 if (Constants.CATEGORY_MAX_LEVEL == level) { return categoryTreeDTO; } //子类目 List child = allList.stream().filter(a -> categoryCode.equals(a.getParentCode())).collect(Collectors.toList()); if (null == child) { return categoryTreeDTO; } categoryTreeDTO.setChildren(child); //组装子类目 for (CategoryTreeDTO dto : child) { assembleTree(dto, allList,remainRecursionCount); } return categoryTreeDTO; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值