java树形结构存储_java树形结构 算法【收藏】

本文介绍了如何使用Java实现树形结构的存储和操作,包括新增、修改和删除节点的详细步骤。通过调整节点的左右值(lft和rgt)来维护树的平衡。新增节点时,首先找到父节点的lft值,然后更新所有受影响的节点;修改节点时,需要考虑旧父节点和新父节点的影响,调整多个位置;删除节点时,只需减小大于删除节点lft值的节点的lft和rgt。所有操作均涉及对数据库中节点数据的更新。
摘要由CSDN通过智能技术生成

2be4e28de31a69b778ae054f46a69123.png这样我们查找该节点的所有子节点,则只需要查找id在lft和rgt之间的所有节点即可。

1.查找该节点的所有子节点的Sql语句为:

Sql代码 icon_copy.gif

select*fromtb_subject s,tb_subject twheres.lftbetweent.lftandt.rgtandt.id=1

select * from tb_subject s,tb_subject t where s.lft between t.lft and t.rgt and t.id=1

2.查找该节点的所有父节点的sql语句为:

Sql代码 icon_copy.gif

selects.*fromtb_subject s,tb_subject twheres.lft1ands.rgt>t.rgtandt.id=1

select s.* from tb_subject s,tb_subject t where s.lft1 and s.rgt>t.rgt and t.id=1

下面来详细讲解下,怎么用java来实现这种算法。

1.新增节点

新增节点比较简单,基本步骤为

A.查找当前插入节点的父节点的lft值

B.将树形中所有lft和rgt节点大于父节点左值的节点都+2

C.将父节点左值+1,左值+2分别作为当前节点的lft和rgt

因为项目中采用的是struts2+hibernate3.2+spring2.5的框架,代码如下:

Java代码 icon_copy.gif

publicbooleanonSave(Object entity, Serializable id, Object[] state,

String[] propertyNames, Type[] types) {

if(entityinstanceofHibernateTree) {

HibernateTree tree = (HibernateTree) entity;

Long parentId = tree.getParentId();

String beanName = tree.getClass().getName();

Session session = getSession();

FlushMode model = session.getFlushMode();

session.setFlushMode(FlushMode.MANUAL);

Integer myPosition =newInteger(0);

//查找父节点的左值

if(parentId !=null) {

String hql ="select b.lft from "+ beanName

+" b where b.id=:pid";

myPosition = (Integer) session.createQuery(hql).setLong("pid",

parentId).uniqueResult();

}

//将树形结构中所有大于父节点左值的右节点+2

String hql1 ="update "+ beanName

+" b set b.rgt = b.rgt + 2 WHERE b.rgt > :myPosition";

//将树形结构中所有大于父节点左值的左节点+2

String hql2 ="update "+ beanName

+" b set b.lft = b.lft + 2 WHERE b.lft > :myPosition";

if(!StringUtils.isBlank(tree.getTreeCondition())) {

hql1 +=" and ("+ tree.getTreeCondition() +")";

hql2 +=" and ("+ tree.getTreeCondition() +")";

}

session.createQuery(hql1).setInteger("myPosition", myPosition)

.executeUpdate();

session.createQuery(hql2).setInteger("myPosition", myPosition)

.executeUpdate();

session.setFlushMode(model);

//定位自己的左值(父节点左值+1)和右值(父节点左值+2)

for(inti =0; i 

if(propertyNames[i].equals(HibernateTree.LFT)) {

state[i] = myPosition +1;

}

if(propertyNames[i].equals(HibernateTree.RGT)) {

state[i] = myPosition +2;

}

}

returntrue;

}

returnfalse;

}

public boolean onSave(Object entity, Serializable id, Object[] state,

String[] propertyNames, Type[] types) {

if (entity instanceof HibernateTree) {

HibernateTree tree = (HibernateTree) entity;

Long parentId = tree.getParentId();

String beanName = tree.getClass().getName();

Session session = getSession();

FlushMode model = session.getFlushMode();

session.setFlushMode(FlushMode.MANUAL);

Integer myPosition = new Integer(0);

//查找父节点的左值

if (parentId != null) {

String hql = "select b.lft from " + beanName

+ " b where b.id=:pid";

myPosition = (Integer) session.createQuery(hql).setLong("pid",

parentId).uniqueResult();

}

//将树形结构中所有大于父节点左值的右节点+2

String hql1 = "update " + beanName

+ " b set b.rgt = b.rgt + 2 WHERE b.rgt > :myPosition";

//将树形结构中所有大于父节点左值的左节点+2

String hql2 = "update " + beanName

+ " b set b.lft = b.lft + 2 WHERE b.lft > :myPosition";

if (!StringUtils.isBlank(tree.getTreeCondition())) {

hql1 += " and (" + tree.getTreeCondition() + ")";

hql2 += " and (" + tree.getTreeCondition() + ")";

}

session.createQuery(hql1).setInteger("myPosition", myPosition)

.executeUpdate();

session.createQuery(hql2).setInteger("myPosition", myPosition)

.executeUpdate();

session.setFlushMode(model);

//定位自己的左值(父节点左值+1)和右值(父节点左值+2)

for (int i = 0; i < propertyNames.length; i++) {

if (propertyNames[i].equals(HibernateTree.LFT)) {

state[i] = myPosition + 1;

}

if (propertyNames[i].equals(HibernateTree.RGT)) {

state[i] = myPosition + 2;

}

}

return true;

}

return false;

}

2.修改节点

修改的时候比较麻烦,具体步骤为:

在修改lft和rgt之前,当前节点的父节点id已经改变

a.查出当前节点的左右节点(nodelft、nodergt),并nodergt-nodelft+1 = span,获取父节点的左节点parentlft

b.将所有大于parentlft的lft(左节点)、rgt(右节点)的值+span

c.查找当前节点的左右节点(nodelft、nodergt),并parentlft-nodelft+1 = offset

d.将所有lft(左节点) between nodelft and nodergt的值+offset

e.将所有大于nodergt的lft(左节点)、rgt(右节点)的值-span

Java代码如下:

Java代码 icon_copy.gif

publicvoidupdateParent(HibernateTree tree, HibernateTree preParent,

HibernateTree curParent) {

if(preParent !=null&& preParent !=null

&& !preParent.equals(curParent)) {

String beanName = tree.getClass().getName();

// 获得节点位置

String hql ="select b.lft,b.rgt from "+ beanName

+" b where b.id=:id";

Object[] position = (Object[])super.createQuery(hql).setLong(

"id", tree.getId()).uniqueResult();

System.out.println(hql+"| id = "+tree.getId());

intnodeLft = ((Number) position[0]).intValue();

intnodeRgt = ((Number) position[1]).intValue();

intspan = nodeRgt - nodeLft +1;

// 获得当前父节点左位置

hql ="select b.lft from "+ beanName +" b where b.id=:id";

intparentLft = ((Number)super.createQuery(hql).setLong("id",

curParent.getId()).uniqueResult()).intValue();

System.out.println(hql+"| id = "+curParent.getId());

// 先空出位置

String hql1 ="update "+ beanName +" b set b.rgt = b.rgt + "

+ span +" WHERE b.rgt > :parentLft";

String hql2 ="update "+ beanName +" b set b.lft = b.lft + "

+ span +" WHERE b.lft > :parentLft";

if(!StringUtils.isBlank(tree.getTreeCondition())) {

hql1 +=" and ("+ tree.getTreeCondition() +")";

hql2 +=" and ("+ tree.getTreeCondition() +")";

}

super.createQuery(hql1).setInteger("parentLft", parentLft)

.executeUpdate();

super.createQuery(hql2).setInteger("parentLft", parentLft)

.executeUpdate();

System.out.println(hql1+"| parentLft = "+parentLft);

System.out.println(hql2+"| parentLft = "+parentLft);

// 再调整自己

hql ="select b.lft,b.rgt from "+ beanName +" b where b.id=:id";

position = (Object[])super.createQuery(hql).setLong("id",

tree.getId()).uniqueResult();

System.out.println(hql+"| id = "+tree.getId());

nodeLft = ((Number) position[0]).intValue();

nodeRgt = ((Number) position[1]).intValue();

intoffset = parentLft - nodeLft +1;

hql ="update "

+ beanName

+" b set b.lft=b.lft+:offset, b.rgt=b.rgt+:offset WHERE b.lft between :nodeLft and :nodeRgt";

if(!StringUtils.isBlank(tree.getTreeCondition())) {

hql +=" and ("+ tree.getTreeCondition() +")";

}

super.createQuery(hql).setParameter("offset", offset)

.setParameter("nodeLft", nodeLft).setParameter("nodeRgt",

nodeRgt).executeUpdate();

System.out.println(hql+"| offset = "+offset+" | nodelft = "+nodeLft+" | nodergt = "+ nodeRgt);

// 最后删除(清空位置)

hql1 ="update "+ beanName +" b set b.rgt = b.rgt - "+ span

+" WHERE b.rgt > :nodeRgt";

hql2 ="update "+ beanName +" b set b.lft = b.lft - "+ span

+" WHERE b.lft > :nodeRgt";

if(tree.getTreeCondition() !=null) {

hql1 +=" and ("+ tree.getTreeCondition() +")";

hql2 +=" and ("+ tree.getTreeCondition() +")";

}

super.createQuery(hql1).setParameter("nodeRgt", nodeRgt)

.executeUpdate();

super.createQuery(hql2).setParameter("nodeRgt", nodeRgt)

.executeUpdate();

System.out.println(hql1+"| nodeRgt = "+nodeRgt);

System.out.println(hql2+"| nodeRgt = "+nodeRgt);

}

}

public void updateParent(HibernateTree tree, HibernateTree preParent,

HibernateTree curParent) {

if (preParent != null && preParent != null

&& !preParent.equals(curParent)) {

String beanName = tree.getClass().getName();

// 获得节点位置

String hql = "select b.lft,b.rgt from " + beanName

+ " b where b.id=:id";

Object[] position = (Object[]) super.createQuery(hql).setLong(

"id", tree.getId()).uniqueResult();

System.out.println(hql+"| id = "+tree.getId());

int nodeLft = ((Number) position[0]).intValue();

int nodeRgt = ((Number) position[1]).intValue();

int span = nodeRgt - nodeLft + 1;

// 获得当前父节点左位置

hql = "select b.lft from " + beanName + " b where b.id=:id";

int parentLft = ((Number) super.createQuery(hql).setLong("id",

curParent.getId()).uniqueResult()).intValue();

System.out.println(hql+"| id = "+curParent.getId());

// 先空出位置

String hql1 = "update " + beanName + " b set b.rgt = b.rgt + "

+ span + " WHERE b.rgt > :parentLft";

String hql2 = "update " + beanName + " b set b.lft = b.lft + "

+ span + " WHERE b.lft > :parentLft";

if (!StringUtils.isBlank(tree.getTreeCondition())) {

hql1 += " and (" + tree.getTreeCondition() + ")";

hql2 += " and (" + tree.getTreeCondition() + ")";

}

super.createQuery(hql1).setInteger("parentLft", parentLft)

.executeUpdate();

super.createQuery(hql2).setInteger("parentLft", parentLft)

.executeUpdate();

System.out.println(hql1+"| parentLft = "+parentLft);

System.out.println(hql2+"| parentLft = "+parentLft);

// 再调整自己

hql = "select b.lft,b.rgt from " + beanName + " b where b.id=:id";

position = (Object[]) super.createQuery(hql).setLong("id",

tree.getId()).uniqueResult();

System.out.println(hql+"| id = "+tree.getId());

nodeLft = ((Number) position[0]).intValue();

nodeRgt = ((Number) position[1]).intValue();

int offset = parentLft - nodeLft + 1;

hql = "update "

+ beanName

+ " b set b.lft=b.lft+:offset, b.rgt=b.rgt+:offset WHERE b.lft between :nodeLft and :nodeRgt";

if (!StringUtils.isBlank(tree.getTreeCondition())) {

hql += " and (" + tree.getTreeCondition() + ")";

}

super.createQuery(hql).setParameter("offset", offset)

.setParameter("nodeLft", nodeLft).setParameter("nodeRgt",

nodeRgt).executeUpdate();

System.out.println(hql+"| offset = "+offset+" | nodelft = "+nodeLft+" | nodergt = "+ nodeRgt);

// 最后删除(清空位置)

hql1 = "update " + beanName + " b set b.rgt = b.rgt - " + span

+ " WHERE b.rgt > :nodeRgt";

hql2 = "update " + beanName + " b set b.lft = b.lft - " + span

+ " WHERE b.lft > :nodeRgt";

if (tree.getTreeCondition() != null) {

hql1 += " and (" + tree.getTreeCondition() + ")";

hql2 += " and (" + tree.getTreeCondition() + ")";

}

super.createQuery(hql1).setParameter("nodeRgt", nodeRgt)

.executeUpdate();

super.createQuery(hql2).setParameter("nodeRgt", nodeRgt)

.executeUpdate();

System.out.println(hql1+"| nodeRgt = "+nodeRgt);

System.out.println(hql2+"| nodeRgt = "+nodeRgt);

}

}

3.删除节点

删除节点也比较简单,具体步骤为:

A.查找要删除节点的lft值

B.将所有lft和rgt大于删除节点lft值的都-2

Java代码如下:

Java代码 icon_copy.gif

publicvoidonDelete(Object entity, Serializable id, Object[] state,

String[] propertyNames, Type[] types) {

if(entityinstanceofHibernateTree) {

HibernateTree tree = (HibernateTree) entity;

String beanName = tree.getClass().getName();

Session session = getSession();

FlushMode model = session.getFlushMode();

session.setFlushMode(FlushMode.MANUAL);

//查找要删除的节点的左值

String hql ="select b.lft from "+ beanName +" b where b.id=:id";

Integer myPosition = (Integer) session.createQuery(hql).setLong(

"id", tree.getId()).uniqueResult();

//将所有大于删除节点左值的rgt都-2

String hql1 ="update "+ beanName

+" b set b.rgt = b.rgt - 2 WHERE b.rgt > :myPosition";

//将所有大于删除节点左值的lft都-2

String hql2 ="update "+ beanName

+" b set b.lft = b.lft - 2 WHERE b.lft > :myPosition";

if(tree.getTreeCondition() !=null) {

hql1 +=" and ("+ tree.getTreeCondition() +")";

hql2 +=" and ("+ tree.getTreeCondition() +")";

}

session.createQuery(hql1).setInteger("myPosition", myPosition)

.executeUpdate();

session.createQuery(hql2).setInteger("myPosition", myPosition)

.executeUpdate();

session.setFlushMode(model);

}

}

public void onDelete(Object entity, Serializable id, Object[] state,

String[] propertyNames, Type[] types) {

if (entity instanceof HibernateTree) {

HibernateTree tree = (HibernateTree) entity;

String beanName = tree.getClass().getName();

Session session = getSession();

FlushMode model = session.getFlushMode();

session.setFlushMode(FlushMode.MANUAL);

//查找要删除的节点的左值

String hql = "select b.lft from " + beanName + " b where b.id=:id";

Integer myPosition = (Integer) session.createQuery(hql).setLong(

"id", tree.getId()).uniqueResult();

//将所有大于删除节点左值的rgt都-2

String hql1 = "update " + beanName

+ " b set b.rgt = b.rgt - 2 WHERE b.rgt > :myPosition";

//将所有大于删除节点左值的lft都-2

String hql2 = "update " + beanName

+ " b set b.lft = b.lft - 2 WHERE b.lft > :myPosition";

if (tree.getTreeCondition() != null) {

hql1 += " and (" + tree.getTreeCondition() + ")";

hql2 += " and (" + tree.getTreeCondition() + ")";

}

session.createQuery(hql1).setInteger("myPosition", myPosition)

.executeUpdate();

session.createQuery(hql2).setInteger("myPosition", myPosition)

.executeUpdate();

session.setFlushMode(model);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值