Java递归实现删除树形结构的任一节点

要删除树形结构的节点,需考虑两件事:
1.要删除的节点若包含子节点,则需删除该节点及其所有子节点;
2.如果要删除的节点的父节点不包含除该节点外的其它子节点,则该父节点变为叶子;
另外,这两件事需要包含在同一事务中,具有原子性。
下面,先来考虑第一件事:
要遍历树形结构中的一个节点及其子节点,采用递归会比较方便,首先需要一个方法,来将这两件事包含在一起,于是要构建一个方法delClasses


/**
     * 根据classes_id 删除班级节点
     * @param classes_id
     */
public void delClasses(int classes_id) {
        Connection conn = null;
        try {
            conn = DbUtil.getConnection();
            //设置手动提交事务,两个事务需使用同一个Connection
            conn.setAutoCommit(false);
            //设置班级节点的父节点的leaf
            setLeafByDel(conn,classes_id);
            //方法复用
            delClasses(conn,classes_id);
            //两件事完成后,提交事务
            conn.commit();
        } catch(Exception e) {
        //出现异常,则回滚事务
            DbUtil.rollBack(conn);
            e.printStackTrace();
        } finally {
            DbUtil.close(conn);
        }
    }

然后,再考虑删除班级的主方法delClasses(Connection conn,int classes_id),在设计该方法前,需要做些准备,需要一个方法来得到该节点下所有子节点。该方法需要返回Class类型的集合类对象。


/**
     * 根据父节点id的到所有的classes对象
     * @param pid 当前节点的id
     * @return 所有子节点的对象
     * @throws SQLException 
     */
    private List<Class> findClassesByPid(int pid) throws SQLException {
    //定义集合类用来装子节点对应的class对象
        List<Class> classesList = new ArrayList<Class>();
        Connection conn = null;
        PreparedStatement psta = null;
        ResultSet rs = null;
        String sql = "use 成绩管理系统 select * from t_class where pid = ?";
        conn = DbUtil.getConnection();
        try {
            psta = conn.prepareStatement(sql);
            psta.setInt(1, pid);
            rs = psta.executeQuery();
            while(rs.next()) {
                Class classes = new Class();
                classes.setClassId(rs.getInt("class_id"));
                classes.setClassName(rs.getString("class_name"));
                classes.setLeaf(rs.getInt("leaf"));
                classes.setPid(rs.getInt("pid"));
                classesList.add(classes);
            }
        } finally {
            DbUtil.close(rs);
            DbUtil.close(psta);
            DbUtil.close(conn);
        }
        //返回子节点对象集合
        return classesList;
    }

下面,可以写递归删除当前节点及其子节点的方法了。


/**
     * 删除班级,递归实现,删除该节点下所有子节点
     * @param conn
     * @param classes_id 要删除的班级编号
     * @throws SQLException 
     */
    public void delClasses(Connection conn,int classes_id) throws SQLException {
        String sql = "use 成绩管理系统 delete from t_class where class_id = ?";
        PreparedStatement psta = null;
        //根据当前节点的id得到当前节点对应的对象,该方法在上一个例子中已经定义
        int leaf = findClassesById(classes_id).getLeaf();
        try {   
            psta = conn.prepareStatement(sql);
            psta.setInt(1, classes_id);
            psta.executeUpdate();
            //当前节点不是叶子节点,则需删除其所属的所有子节点
            if(leaf == 0) {
            //得到该节点下的所有子节点,存放在classesList中
                 List<Class> classesList = findClassesByPid(classes_id);
                 //遍历集合类classesList,递归调用删除方法
                 for(Iterator<Class> iter = classesList.iterator(); iter.hasNext();) {
                     Class classes = iter.next();
                     delClasses(conn,classes.getClassId());
                 }
            }
        } finally {
            DbUtil.close(psta);
        }
    }

删除完成之后,需要考虑另外一个问题,即该节点父节点的leaf问题,要解决这个问题,首先需要得到该节点的父节点,再得到该父节点所有的子节点,最后根据该父节点所有子节点的个数来决定设置leaf。
首先,需要一个方法来得到该节点的父节点。该方法的参数为当前节点的pid,即其父节点的id


/**
     * 根据当前节点返回其父节点的class对象
     * @param classes_id 当前节点id
     * @return 当前节点的父节点对象
     * @throws SQLException
     */
    private Class findParentBySon(int classes_id) throws SQLException {
        Class classes = new Class();
        classes = findClassesById(classes_id);
        String sql = "use 成绩管理系统 select * from t_class where class_id = ?";
        PreparedStatement psta = null;
        Connection conn = null;
        ResultSet rs = null;
        try {
            conn = DbUtil.getConnection();
            psta = conn.prepareStatement(sql);
            //将当前节点的pid传入sql语句
            psta.setInt(1, classes.getPid());
            rs = psta.executeQuery();
            while(rs.next()) {
                classes.setClassId(rs.getInt("class_id"));
                classes.setClassName(rs.getString("class_name"));
                classes.setLeaf(rs.getInt("leaf"));
                classes.setPid(rs.getInt("pid"));
            }
            return classes;
        } finally {
            DbUtil.close(rs);
            DbUtil.close(psta);
            DbUtil.close(conn);
        }
    }

然后,再来写修改父节点leaf的方法,该方法应放于删除方法之前执行,即先修改父节点的leaf,再执行删除操作。所以要判断将删除的节点的父节点的子节点的个数是否为1,若为1,则将父节点设置为叶子。若父节点的子节点个数大于1,则不需要设置父节点的leaf。


/**
     * 根据删除的节点,设置父节点的leaf,若父节点没有其他子节点,则将父节点设置为叶子;否则不变
     * @param conn 
     * @param classes_id 子节点的id
     * @throws SQLException 
     */
    private void setLeafByDel(Connection conn,int classes_id) throws SQLException {
    //用来装父节点所有的子节点
        List<Class> classesList = new ArrayList<Class>();
        Class classes = new Class();
        try {
            //得到父节点对象
            classes = findParentBySon(classes_id);
            //得到父节点所有的子节点,存放在classesList中
            classesList = findClassesByPid(classes.getClassId());
            //判断classesList 的元素个数,如为1,则需要将该父节点设置为叶子
            if(classesList.size() == 1) {
            //设置父节点为leaf
                modifyLeaf(conn,classes.getClassId(),1);
            }
        } finally {
            null;
        }
    }

删除节点结束

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值