Java再帰実装ツリー構造のいずれかのノードの削除

9606 ワード

ツリー構造のノードを削除するには、2つのことを考慮します:1.削除するノードにサブノードが含まれている場合は、そのノードとそのすべてのサブノードを削除する必要があります.2.削除するノードの親ノードに、そのノード以外の子ノードが含まれていない場合、親ノードはリーフになります.また、この2つのことは同じ事務に含まれ、原子性を持つ必要があります.次に、まず最初のことを考えます.ツリー構造のノードとそのサブノードを巡回するには、再帰を採用するのが便利です.まず、この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 findClassesByPid(int pid) throws SQLException {
    //              class  
        List classesList = new ArrayList();
        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 classesList = findClassesByPid(classes_id);
                 //     classesList,        
                 for(Iterator 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 classesList = new ArrayList();
        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;
        }
    }

ノードの削除の終了