【DRP】删除递归树的操作

正如图呈现的树结构。本文从任意节点删除树形结构。提供解决方案

图中,不包括其他结点的是叶子结点。包括其他结点的是父结点,即不是叶子结点。

一 本文的知识点:

(1)递归调用:

由于待删除的结点的层次是不确定的,假设是叶子结点则能够直接获取id直接删除,如:北京中医医院、华北区。假设待删除的结点是父结点,则须要继续向下查询,依次遍历出其子结点,从下往上依次删除,如‘华北区’。因此我们使用递归调用。

(2)保证事务的原子性

如果待删除的结点是‘华北区’。则相当于删除了3条信息(华北区、北京市、北京中医医院)。通常觉得同一时候删除多条数据,是具有原子性的。

删除100条信息,相当于一个事务。要么一起删除。要么都不删除。

事务控制,表现为双方面:一个是递归删除过程中採用一个Connection(同一时候防止递归中循环调用导致Connection效率不高)。还有一个是设置手动提交。

(3)异常是throws ?还是catch?

主方法delClientOrRegion为public 採用try…catch……finally打印堆栈中的错误信息。主方法中调用的方法。如:recursionDelNode、getChildren、modifyIsLeafField。均为private仅供方法内部调用。同一时候採用throws
SQLException抛出异常,而不是catch捕捉异常。

这是由于如果getChildren内部catch了错误,打印了堆栈信息。那么上面一层不知道它出错的话。因此就不会事务回滚。

因此建议内部抛出异常throws
SQLException,外部使用捕获异常try catch

(4)树的几种设计方式

1)不带冗余字段,id主键,pid父结点主键

2)带冗余字段。id、pid、isleaf是否为叶子、childrencount孩子结点的数目

3)採用固定的字符串00010010001

00全部分销商

01华北区

001北京市

0001北京中医医院

(本数据库设计採用:id主键、pid父结点主键、is_leaf是否为叶子结点)

(5)业务逻辑解析,如果待删除结点为‘北京市’

1)保存父结点对象。即:获取‘北京市’的父结点‘华北区’的id。

2)递归删除树结点。即:删除‘北京市’同一时候还要删除其孩子结点‘北京中医医院’。

删除的顺序也是有要求的,先删除孩子,后删除父亲。即先删除‘北京中医医院’。后删除‘北京市’。这一点在递归代码中有所体现。

3)假设父结点下没有子结点,则改动为叶子结点。

即:假设‘华北区’没有孩子。则须要设置‘华北区’为叶子结点。

二 部分代码例如以下:

package com.bjpowernode.drp.basedata.manager;

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

import com.bjpowernode.drp.basedata.domain.AimClient;
import com.bjpowernode.drp.basedata.domain.Client;
import com.bjpowernode.drp.util.Constants;
import com.bjpowernode.drp.util.DbUtil;
import com.bjpowernode.drp.util.IdGenerator;
import com.bjpowernode.drp.util.PageModel;
import com.bjpowernode.drp.util.datadict.domain.ClientLevel;

/**
 * 採用单例实现
 * @author Administrator
 *
 */
public class ClientManager {

	private static ClientManager instance = new ClientManager();

	private ClientManager() {}

	public static ClientManager getInstance() {
		return instance;
	}

		/**
	 * 删除分销商或区域
	 * @param id
	 */
	public void delClientOrRegion(int id) {
		Connection conn = null;
		try {
			conn = DbUtil.getConnection();
			//手动控制事务的开启
			DbUtil.beginTransaction(conn);

			//保存父节点对象
			Client currentNode = findClientOrRegionById(id);

			//递归删除树节点
			recursionDelNode(conn, id);

			//假设父节点下没有子节点
			if (getChildren(conn, currentNode.getPid()) == 0) {
				//改动为叶子
				modifyIsLeafField(conn, currentNode.getPid(), Constants.YES);
			}
			//提交事务
			DbUtil.commitTransaction(conn);
		}catch(Exception e) {
			//假设出错则打印堆栈信息
			e.printStackTrace();
			//事务回滚
			DbUtil.rollbackTransaction(conn);
		}finally {
			//事务重置
			DbUtil.resetConnection(conn);
			//关闭数据库连接
			DbUtil.close(conn);
		}
	}
	/**
	 * 递归删除
	 * @param conn
	 * @param id
	 */
	private void recursionDelNode(Connection conn, int id)
	throws SQLException {
		//依据
		String sql = "select * from t_client where pid=?

";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = DbUtil.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, id);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				//假设是不叶子节点。则递归调用
				if (Constants.NO.equals(rs.getString("is_leaf"))) {
					recursionDelNode(conn, rs.getInt("id"));
				}
				//假设是叶子节点。则直接删除
				delNode(conn, rs.getInt("id"));
			}
			//删除自身
			delNode(conn, id);
		}finally {
			DbUtil.close(rs);
			DbUtil.close(pstmt);
		}
	}
		/**
	 * 取得指定节点的孩子数目
	 * @param conn
	 * @param id
	 * @return
	 */
	private int getChildren(Connection conn, int id)
	throws SQLException {
		//sql语句通过孩子pid的个数,推断是否为叶子节点
		String sql = "select count(*) as c from t_client where pid=?";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		int count = 0;
		try {
			conn = DbUtil.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, id);
			rs = pstmt.executeQuery();
			rs.next();
			count = rs.getInt("c");
		}finally {
			DbUtil.close(rs);
			DbUtil.close(pstmt);
		}
		return count;
	}
		/**
	 * 改动isLeaf字段
	 * @param conn
	 * @param id
	 * @param leaf Y/N
	 */
	private void modifyIsLeafField(Connection conn, int id, String leaf)
	throws SQLException {
		//假设待删除的节点的父节点没有其它孩子节点,则设置为叶子状态
		String sql = "update t_client set is_leaf=?

where id=?

";
		PreparedStatement pstmt = null;
		try {
			conn = DbUtil.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, leaf);
			pstmt.setInt(2, id);
			pstmt.executeUpdate();
		} finally {
			DbUtil.close(pstmt);
		}
	}
}

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2025-01-03 21:35:24

【DRP】删除递归树的操作的相关文章

数据结构之关于树的操作(树的递归和非递归遍历)-(四补)

前面写了一些关于树的操作,但是没有实现树的遍历的非递归写法. 通常树有四种遍历方法:1.层次遍历(需要用到树的高度,此文没有考虑) 2.前序遍历(根左右):3.中序遍历(左根右):4.后序遍历(左右根) 树的结构如下: 层次遍历:123456789 前序遍历:124895367 中序遍历:849251637 后序遍历:894526731 java代码实现三种遍历的递归和和非递归实现 package com.lip.datastructure.tree; import java.util.Stac

ext 树节点操作

ext 树节点操作 tree :树    node:节点 1.全部展开 tree.expandAll(); 2.全部收缩 tree.collapseAll(); 3.得到父节点 node.parentNode 4.判断是否有父节点 node.parentNode==null 5.判断是否有子节点 node.hasChildNodes() 6.获取下一级所有子节点 node.eachChild(function(child) { }) 7.获取选择的节点 tree.getSelectionMode

wikioi 1285 伸展树delete操作

题目描述 Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值.这样他就能够很方便的处理整个领养宠物的过程了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少. 1. 被遗弃的宠物过多时,假若到

Phone List(简单的字典树插入操作)

Phone List Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11655    Accepted Submission(s): 3970 Problem Description Given a list of phone numbers, determine if it is consistent in the sense th

hdu 3473 Minimum Sum(划分树-sum操作)

划分树.只是考虑求当前区间大于第k值的值得和,和小于第k值的和.显然可以在查询的时候直接搞出来.sum[d][i]表示第d层子区间l,r种l-i的和.写错了一个下标,检查了半辈子... #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue&g

哈弗曼树及其操作

1.哈弗曼树的节点声明 1 package com.neusoft.Tree; 2 3 public class HuffmanNode { 4 public int weight; 5 //加入哈夫曼树的标志,flag=0表示该节点没有加入哈夫曼树,=1表示加入 6 public int flag; 7 public HuffmanNode parent,lchild,rchild; 8 public HuffmanNode() { 9 this(0); 10 } 11 public Huff

单链表的头插、尾插、删除、合并等操作

单链表的头插.尾插.删除.合并等操作实现代码如下: #include<iostream> using namespace std; //单链表的存储结构 typedef struct Node { int data; struct Node* next; }Node,*LinkList;//LinkList为结构指针类型 //初始化单链表 void InitList(LinkList *L) { *L = (LinkList)malloc(sizeof(Node));//建立头结点 (*L)-

C++文件的创建、删除、更改文件名操作(代码)

#pragma once #ifndef __FileOperation_H__ #define __FileOperation_H__ #include <string> using namespace std; class FileOperation { public: // 构造函数,dir为文件夹名称:标注.书签.试题.模型及动画.media.界面等 FileOperation( string dir ); ~FileOperation(void); // 创建一个文件名为filena

(转)递归树求递归算法的时间复杂度

本文转载:http://www.cnblogs.com/wu8685/archive/2010/12/21/1912347.html 递归算法时间复杂度的计算方程式一个递归方程: 在引入递归树之前可以考虑一个例子: T(n) = 2T(n/2) + n2 迭代2次可以得: T(n) = n2 + 2(2T(n/4) + (n/2) 2) 还可以继续迭代,将其完全展开可得: T(n) = n2 + 2((n/2) 2 + 2((n/22)2 + 2((n/23) 2 + 2((n/24) 2 +-