R树的Java实现

以下为R树插入和删除Java代码实现,共7个类文件

package com.njupt.rtree;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
 
import com.njupt.constants.Constants;
 
/**
 * @ClassName RTree 
 * @Description 
 */
public class RTree 
{
	/**
	 * 根节点
	 */
	private RTNode root;
	
	/**
	 * 树类型
	 */
	private int tree_type;
	
	/**
	 * 结点容量
	 */
	private int nodeCapacity = -1;
	
	/**
	 * 结点填充因子
	 */
	private float fillFactor = -1;
	
	private int dimension ;
	
	public RTree(int capacity, float fillFactor, int type, int dimension)
	{
		this.fillFactor = fillFactor;
		tree_type = type;
		nodeCapacity = capacity;
		this.dimension = dimension;
		root = new RTDataNode(this,Constants.NULL);
	}
	
	/**
	 * @return RTree的维度
	 */
	public int getDimension()
	{
		return dimension;
	}
	
	public void setRoot(RTNode root)
	{
		this.root = root;
	}
	
	public float getFillFactor()
	{
		return fillFactor;
	}
	
	/**
	 * @return 返回结点容量
	 */
	public int getNodeCapacity()
	{
		return nodeCapacity;
	}
	
	/**
	 * @return 返回树的类型
	 */
	public int getTreeType()
	{
		return tree_type;
	}
	
	/**
	 * 向Rtree中插入Rectangle

* 1、先找到合适的叶节点
* 2、再向此叶节点中插入
* @param rectangle */ public boolean insert(Rectangle rectangle) { if(rectangle == null) throw new IllegalArgumentException("Rectangle cannot be null."); if(rectangle.getHigh().getDimension() != getDimension()) { throw new IllegalArgumentException("Rectangle dimension different than RTree dimension."); } RTDataNode leaf = root.chooseLeaf(rectangle); return leaf.insert(rectangle); } /** * 从R树中删除Rectangle

* 1、寻找包含记录的结点--调用算法findLeaf()来定位包含此记录的叶子结点L,如果没有找到则算法终止。
* 2、删除记录--将找到的叶子结点L中的此记录删除
* 3、调用算法condenseTree
* @param rectangle * @return */ public int delete(Rectangle rectangle) { if(rectangle == null) { throw new IllegalArgumentException("Rectangle cannot be null."); } if(rectangle.getHigh().getDimension() != getDimension()) { throw new IllegalArgumentException("Rectangle dimension different than RTree dimension."); } RTDataNode leaf = root.findLeaf(rectangle); if(leaf != null) { return leaf.delete(rectangle); } return -1; } /** * 从给定的结点root开始遍历所有的结点 * @param node * @return 所有遍历的结点集合 */ public List traversePostOrder(RTNode root) { if(root == null) throw new IllegalArgumentException("Node cannot be null."); List list = new ArrayList(); list.add(root); if(! root.isLeaf()) { for(int i = 0; i < root.usedSpace; i ++) { List a = traversePostOrder(((RTDirNode)root).getChild(i)); for(int j = 0; j < a.size(); j ++) { list.add(a.get(j)); } } } return list; } public static void main(String[] args) throws Exception { // RTree tree = new RTree(3, 0.4f, Constants.RTREE_QUADRATIC, 2); // // float[] f = {10, 20, 40, 70, //1 // 30, 10, 70, 15, // 100, 70, 110, 80, //3 // 0, 50, 30, 55, // 13, 21, 54, 78, //5 // 3, 8, 23, 34, // 200, 29, 202, 50, // 34, 1, 35, 1, //8 // 201, 200, 234, 203, // 56, 69, 58, 70, //10 // 2, 67, 270, 102, // 1, 10, 310, 20, //12 // 23, 12, 345, 120, // 5, 34, 100, 340, // 19,100,450,560, //15 // 12,340,560,450, // 34,45,190,590, // 24,47,770,450, //18 // // 91,99,390,980, // 89,10,99,100, //20 // 10,29,400,990, // 110,220,220,330, // 123,24,234,999 //23 // }; // // //插入结点 // for(int i = 0; i < f.length;) // { // Point p1 = new Point(new float[]{f[i++],f[i++]}); // Point p2 = new Point(new float[]{f[i++],f[i++]}); // final Rectangle rectangle = new Rectangle(p1, p2); // tree.insert(rectangle); // // Rectangle[] rectangles = tree.root.datas; // System.out.println(tree.root.level); // for(int j = 0; j < rectangles.length; j ++) // System.out.println(rectangles[j]); // } // System.out.println("---------------------------------"); // System.out.println("Insert finished."); // //删除结点 // System.out.println("---------------------------------"); // System.out.println("Begin delete."); // // for(int i = 0; i < f.length;) // { // Point p1 = new Point(new float[]{f[i++],f[i++]}); // Point p2 = new Point(new float[]{f[i++],f[i++]}); // final Rectangle rectangle = new Rectangle(p1, p2); // tree.delete(rectangle); // // Rectangle[] rectangles = tree.root.datas; // System.out.println(tree.root.level); // for(int j = 0; j < rectangles.length; j ++) // System.out.println(rectangles[j]); // } // // System.out.println("---------------------------------"); // System.out.println("Delete finished."); // Rectangle[] rectangles = tree.root.datas; // for(int i = 0; i < rectangles.length; i ++) // System.out.println(rectangles[i]); System.out.println("---------------------------------"); RTree tree = new RTree(5, 0.4f, Constants.RTREE_QUADRATIC,2); BufferedReader reader = new BufferedReader(new FileReader(new File("d:\\LB.txt"))); String line ; while((line = reader.readLine()) != null) { String[] splits = line.split(" "); float lx = Float.parseFloat(splits[1]); float ly = Float.parseFloat(splits[2]); float hx = Float.parseFloat(splits[3]); float hy = Float.parseFloat(splits[4]); Point p1 = new Point(new float[]{lx,ly}); Point p2 = new Point(new float[]{hx,hy}); final Rectangle rectangle = new Rectangle(p1, p2); tree.insert(rectangle); Rectangle[] rectangles = tree.root.datas; System.out.println(tree.root.level); for(int j = 0; j < rectangles.length; j ++) System.out.println(rectangles[j]); } //删除结点 System.out.println("---------------------------------"); System.out.println("Begin delete."); reader = new BufferedReader(new FileReader(new File("d:\\LB.txt"))); while((line = reader.readLine()) != null) { String[] splits = line.split(" "); float lx = Float.parseFloat(splits[1]); float ly = Float.parseFloat(splits[2]); float hx = Float.parseFloat(splits[3]); float hy = Float.parseFloat(splits[4]); Point p1 = new Point(new float[]{lx,ly}); Point p2 = new Point(new float[]{hx,hy}); final Rectangle rectangle = new Rectangle(p1, p2); tree.delete(rectangle); Rectangle[] rectangles = tree.root.datas; System.out.println(tree.root.level); for(int j = 0; j < rectangles.length; j ++) System.out.println(rectangles[j]); } System.out.println("---------------------------------"); System.out.println("Delete finished."); } } package com.njupt.rtree; import java.util.List; import com.njupt.constants.Constants; import com.njupt.spatial.INode; /** * @ClassName RTNode * @Description */ public abstract class RTNode { /** * 结点所在的树 */ protected RTree rtree; /** * 结点所在的层 */ protected int level; /** * 相当于条目 */ protected Rectangle[] datas; // /** // * 结点的容量 // */ // protected int capacity; /** * 父节点 */ protected RTNode parent; /** * 结点已用的空间 */ protected int usedSpace; /** * 记录插入的搜索路径索引 */ protected int insertIndex; /** * 记录删除的查找路径索引 */ protected int deleteIndex; public RTNode(RTree rtree, RTNode parent, int level) { this.rtree = rtree; this.parent = parent; this.level = level; // this.capacity = capacity; datas = new Rectangle[rtree.getNodeCapacity() + 1];//多出的一个用于结点分裂 usedSpace = 0; } /** * @return 返回父节点 */ public RTNode getParent() { return parent; } // /** // * @return 结点容量 // */ // public int getNodeCapacity() // { // return capacity; // } /** * 向结点中添加Rectangle,即添加条目 * @param rectangle */ protected void addData(Rectangle rectangle) { if(usedSpace == rtree.getNodeCapacity()) { throw new IllegalArgumentException("Node is full."); } datas[usedSpace ++] = rectangle; } /** * 删除结点中的第i个条目 * @param i */ protected void deleteData(int i) { if(datas[i + 1] != null) { System.arraycopy(datas, i + 1, datas, i, usedSpace - i -1); datas[usedSpace - 1] = null; } else datas[i] = null; usedSpace --; } /** * 叶节点L中刚刚删除了一个条目,如果这个结点的条目数太少下溢,则删除该结点,同时将该结点中剩余的条目重定位到其他结点中。 * 如果有必要,要逐级向上进行这种删除,调整向上传递的路径上的所有外包矩形,使其尽可能小,直到根节点。 * @param list 存储删除结点中剩余条目 */ protected void condenseTree(List list) { if(isRoot()) { //根节点只有一个条目了,即只有左孩子或者右孩子 if(! isLeaf() && usedSpace == 1) { RTDirNode root = (RTDirNode) this; RTNode child = root.getChild(0); root.children.remove(this);//gc child.parent = null; // if(child.level > 0) // child.level --; rtree.setRoot(child); // //所有结点的level减1,即树降低一层 // List nodes = rtree.traversePostOrder(child); // for(int i = 0; i < nodes.size(); i ++) // { // nodes.get(i).level -= 1; // } } }else{ RTNode parent = getParent(); int min = Math.round(rtree.getNodeCapacity() * rtree.getFillFactor()); if(usedSpace < min) { parent.deleteData(parent.deleteIndex);//其父节点中删除此条目 ((RTDirNode)parent).children.remove(this); this.parent = null; list.add(this);//之前已经把数据删除了 }else{ parent.datas[parent.deleteIndex] = getNodeRectangle(); } parent.condenseTree(list); } } /** * 分裂结点的平方算法

* 1、为两个组选择第一个条目--调用算法pickSeeds()来为两个组选择第一个元素,分别把选中的两个条目分配到两个组当中。
* 2、检查是否已经分配完毕,如果一个组中的条目太少,为避免下溢,将剩余的所有条目全部分配到这个组中,算法终止
* 3、调用pickNext来选择下一个进行分配的条目--计算把每个条目加入每个组之后面积的增量,选择两个组面积增量差最大的条目索引, * 如果面积增量相等则选择面积较小的组,若面积也相等则选择条目数更少的组
* @param rectangle 导致分裂的溢出Rectangle * @return 两个组中的条目的索引 */ protected int[][] quadraticSplit(Rectangle rectangle) { if(rectangle == null) { throw new IllegalArgumentException("Rectangle cannot be null."); } datas[usedSpace] = rectangle; //先添加进去 // if(this instanceof RTDirNode) // { // (RTDirNode)(this).children.add() // } int total = usedSpace + 1; //结点总数 //标记访问的条目 int[] mask = new int[total]; for(int i = 0; i < total; i ++) { mask[i] = 1; } //每个组只是有total/2个条目 int c = total/2 + 1; //每个结点最小条目个数 int minNodeSize = Math.round(rtree.getNodeCapacity() * rtree.getFillFactor()); //至少有两个 if(minNodeSize < 2) minNodeSize = 2; //记录没有被检查的条目的个数 int rem = total; int[] group1 = new int[c];//记录分配的条目的索引 int[] group2 = new int[c];//记录分配的条目的索引 //跟踪被插入每个组的条目的索引 int i1 = 0, i2 = 0; int[] seed = pickSeeds(); group1[i1 ++] = seed[0]; group2[i2 ++] = seed[1]; rem -=2; mask[group1[0]] = -1; mask[group2[0]] = -1; while(rem > 0) { //将剩余的所有条目全部分配到group1组中,算法终止 if(minNodeSize - i1 == rem) { for(int i = 0; i < total; i ++)//总共rem个 { if(mask[i] != -1)//还没有被分配 { group1[i1 ++] = i; mask[i] = -1; rem --; } } //将剩余的所有条目全部分配到group1组中,算法终止 }else if(minNodeSize - i2 == rem) { for(int i = 0; i < total; i ++)//总共rem个 { if(mask[i] != -1)//还没有被分配 { group2[i2 ++] = i; mask[i] = -1; rem --; } } }else { //求group1中所有条目的最小外包矩形 Rectangle mbr1 = (Rectangle) datas[group1[0]].clone(); for(int i = 1; i < i1; i ++) { mbr1 = mbr1.getUnionRectangle(datas[group1[i]]); } //求group2中所有条目的外包矩形 Rectangle mbr2 = (Rectangle) datas[group2[0]].clone(); for(int i = 1; i < i2; i ++) { mbr2 = mbr2.getUnionRectangle(datas[group2[i]]); } //找出下一个进行分配的条目 double dif = Double.NEGATIVE_INFINITY; double areaDiff1 = 0, areaDiff2 = 0; int sel = -1; for(int i = 0; i < total; i ++) { if(mask[i] != -1)//还没有被分配的条目 { //计算把每个条目加入每个组之后面积的增量,选择两个组面积增量差最大的条目索引 Rectangle a = mbr1.getUnionRectangle(datas[i]); areaDiff1 = a.getArea() - mbr1.getArea(); Rectangle b = mbr2.getUnionRectangle(datas[i]); areaDiff2 = b.getArea() - mbr2.getArea(); if(Math.abs(areaDiff1 - areaDiff2) > dif) { dif = Math.abs(areaDiff1 - areaDiff2); sel = i; } } } if(areaDiff1 < areaDiff2)//先比较面积增量 { group1[i1 ++] = sel; }else if(areaDiff1 > areaDiff2) { group2[i2 ++] = sel; }else if(mbr1.getArea() < mbr2.getArea())//再比较自身面积 { group1[i1 ++] = sel; }else if(mbr1.getArea() > mbr2.getArea()) { group2[i2 ++] = sel; }else if(i1 < i2)//最后比较条目个数 { group1[i1 ++] = sel; }else if(i1 > i2) { group2[i2 ++] = sel; }else { group1[i1 ++] = sel; } mask[sel] = -1; rem --; } }//end while int[][] ret = new int[2][]; ret[0] = new int[i1]; ret[1] = new int[i2]; for(int i = 0; i < i1; i ++) { ret[0][i] = group1[i]; } for(int i = 0; i < i2; i ++) { ret[1][i] = group2[i]; } return ret; } /** * 1、对每一对条目E1和E2,计算包围它们的Rectangle J,计算d = area(J) - area(E1) - area(E2);
* 2、Choose the pair with the largest d * @return 返回两个条目如果放在一起会有最多的冗余空间的条目索引 */ protected int[] pickSeeds() { double inefficiency = Double.NEGATIVE_INFINITY; int i1 = 0, i2 = 0; // for(int i = 0; i < usedSpace; i ++) { for(int j = i + 1; j <= usedSpace; j ++)//注意此处的j值 { Rectangle rectangle = datas[i].getUnionRectangle(datas[j]); double d = rectangle.getArea() - datas[i].getArea() - datas[j].getArea(); if(d > inefficiency) { inefficiency = d; i1 = i; i2 = j; } } } return new int[]{i1, i2}; } /** * @return 返回包含结点中所有条目的最小Rectangle */ public Rectangle getNodeRectangle() { if(usedSpace > 0) { Rectangle[] rectangles = new Rectangle[usedSpace]; System.arraycopy(datas, 0, rectangles, 0, usedSpace); return Rectangle.getUnionRectangle(rectangles); }else { return new Rectangle(new Point(new float[]{0,0}), new Point(new float[]{0,0})); } } /** * @return 是否根节点 */ public boolean isRoot() { return (parent == Constants.NULL); } /** * @return 是否非叶子结点 */ public boolean isIndex() { return (level != 0); } /** * @return 是否叶子结点 */ public boolean isLeaf() { return (level == 0); } /** * 步骤CL1:初始化——记R树的根节点为N。
* 步骤CL2:检查叶节点——如果N是个叶节点,返回N
* 步骤CL3:选择子树——如果N不是叶节点,则从N中所有的条目中选出一个最佳的条目F, * 选择的标准是:如果E加入F后,F的外廓矩形FI扩张最小,则F就是最佳的条目。如果有两个 * 条目在加入E后外廓矩形的扩张程度相等,则在这两者中选择外廓矩形较小的那个。
* 步骤CL4:向下寻找直至达到叶节点——记Fp指向的孩子节点为N,然后返回步骤CL2循环运算, * 直至查找到叶节点。

* @param Rectangle * @return RTDataNode */ protected abstract RTDataNode chooseLeaf(Rectangle rectangle); /** * R树的根节点为T,查找包含rectangle的叶子结点

* 1、如果T不是叶子结点,则逐个查找T中的每个条目是否包围rectangle,若包围则递归调用findLeaf()
* 2、如果T是一个叶子结点,则逐个检查T中的每个条目能否匹配rectangle
* @param rectangle * @return 返回包含rectangle的叶节点 */ protected abstract RTDataNode findLeaf(Rectangle rectangle); } package com.njupt.rtree; import java.util.ArrayList; import java.util.List; import com.njupt.constants.Constants; /** * @ClassName RTDataNode * @Description */ public class RTDataNode extends RTNode { public RTDataNode(RTree rTree, RTNode parent) { super(rTree, parent, 0); } /** * 在叶节点中插入Rectangle,插入后如果其父节点不为空则需要向上调整树直到根节点;
* 若插入Rectangle之后超过结点容量则需要分裂结点 * @param rectangle * @return */ public boolean insert(Rectangle rectangle) { if(usedSpace < rtree.getNodeCapacity()) { datas[usedSpace ++] = rectangle; RTDirNode parent = (RTDirNode) getParent(); if(parent != null) parent.adjustTree(this, null); return true; }else{//超过结点容量 RTDataNode[] splitNodes = splitLeaf(rectangle); RTDataNode l = splitNodes[0]; RTDataNode ll = splitNodes[1]; if(isRoot()) { //根节点已满,需要分裂。创建新的根节点 RTDirNode rDirNode = new RTDirNode(rtree, Constants.NULL, level + 1); rtree.setRoot(rDirNode); rDirNode.addData(l.getNodeRectangle()); rDirNode.addData(ll.getNodeRectangle()); ll.parent = rDirNode; l.parent = rDirNode; rDirNode.children.add(l); rDirNode.children.add(ll); }else{//不是根节点 RTDirNode parentNode = (RTDirNode) getParent(); parentNode.adjustTree(l, ll); } } return true; } /** * 插入Rectangle之后超过容量需要分裂 * @param rectangle * @return */ public RTDataNode[] splitLeaf(Rectangle rectangle) { int[][] group = null; switch(rtree.getTreeType()) { case Constants.RTREE_LINEAR: break; case Constants.RTREE_QUADRATIC: group = quadraticSplit(rectangle); break; case Constants.RTREE_EXPONENTIAL: break; case Constants.RSTAR: break; default: throw new IllegalArgumentException("Invalid tree type."); } RTDataNode l = new RTDataNode(rtree, parent); RTDataNode ll = new RTDataNode(rtree, parent); int[] group1 = group[0]; int[] group2 = group[1]; for(int i = 0; i < group1.length; i ++) { l.addData(datas[group1[i]]); } for(int i = 0; i < group2.length; i ++) { ll.addData(datas[group2[i]]); } return new RTDataNode[]{l, ll}; } @Override public RTDataNode chooseLeaf(Rectangle rectangle) { insertIndex = usedSpace;//记录插入路径的索引 return this; } /** * 从叶节点中删除此条目rectangle

* 先删除此rectangle,再调用condenseTree()返回删除结点的集合,把其中的叶子结点中的每个条目重新插入; * 非叶子结点就从此结点开始遍历所有结点,然后把所有的叶子结点中的所有条目全部重新插入 * @param rectangle * @return */ protected int delete(Rectangle rectangle) { for(int i = 0; i < usedSpace; i ++) { if(datas[i].equals(rectangle)) { deleteData(i); List deleteEntriesList = new ArrayList(); condenseTree(deleteEntriesList); //重新插入删除结点中剩余的条目 for(int j = 0; j < deleteEntriesList.size(); j ++) { RTNode node = deleteEntriesList.get(j); if(node.isLeaf())//叶子结点,直接把其上的数据重新插入 { for(int k = 0; k < node.usedSpace; k ++) { rtree.insert(node.datas[k]); } }else{//非叶子结点,需要先后序遍历出其上的所有结点 List traverseNodes = rtree.traversePostOrder(node); //把其中的叶子结点中的条目重新插入 for(int index = 0; index < traverseNodes.size(); index ++) { RTNode traverseNode = traverseNodes.get(index); if(traverseNode.isLeaf()) { for(int t = 0; t < traverseNode.usedSpace; t ++) { rtree.insert(traverseNode.datas[t]); } } } } } return deleteIndex; }//end if }//end for return -1; } @Override protected RTDataNode findLeaf(Rectangle rectangle) { for(int i = 0; i < usedSpace; i ++) { if(datas[i].enclosure(rectangle)) { deleteIndex = i;//记录搜索路径 return this; } } return null; } } package com.njupt.rtree; import java.util.ArrayList; import java.util.List; import com.njupt.constants.Constants; /** * @ClassName RTDirNode * @Description 非叶节点 */ public class RTDirNode extends RTNode { /** * 孩子结点 */ protected List children; public RTDirNode(RTree rtree, RTNode parent, int level) { super(rtree, parent, level); children = new ArrayList(); } /** * @param index * @return 对应索引下的孩子结点 */ public RTNode getChild(int index) { return children.get(index); } @Override public RTDataNode chooseLeaf(Rectangle rectangle) { int index; switch (rtree.getTreeType()) { case Constants.RTREE_LINEAR: case Constants.RTREE_QUADRATIC: case Constants.RTREE_EXPONENTIAL: index = findLeastEnlargement(rectangle); break; case Constants.RSTAR: if(level == 1)//即此结点指向叶节点 { index = findLeastOverlap(rectangle); }else{ index = findLeastEnlargement(rectangle); } break; default: throw new IllegalStateException("Invalid tree type."); } insertIndex = index;//记录插入路径的索引 return getChild(index).chooseLeaf(rectangle); } /** * @param rectangle * @return 返回最小重叠面积的结点的索引,如果重叠面积相等则选择加入此Rectangle后面积增量更小的,如果面积增量还相等则选择自身面积更小的 */ private int findLeastOverlap(Rectangle rectangle) { float overlap = Float.POSITIVE_INFINITY; int sel = -1; for(int i = 0; i < usedSpace; i ++) { RTNode node = getChild(i); float ol = 0; for(int j = 0; j < node.datas.length; j ++) { ol += rectangle.intersectingArea(node.datas[j]); } if(ol < overlap) { overlap = ol;//记录重叠面积最小的 sel = i;//记录第几个孩子的索引 }else if(ol == overlap)//如果重叠面积相等则选择加入此Rectangle后面积增量更小的,如果面积增量还相等则选择自身面积更小的 { double area1 = datas[i].getUnionRectangle(rectangle).getArea() - datas[i].getArea(); double area2 = datas[sel].getUnionRectangle(rectangle).getArea() - datas[sel].getArea(); if(area1 == area2) { sel = (datas[sel].getArea() <= datas[i].getArea()) ? sel : i; }else{ sel = (area1 < area2) ? i : sel; } } } return sel; } /** * @param rectangle * @return 面积增量最小的结点的索引,如果面积增量相等则选择自身面积更小的 */ private int findLeastEnlargement(Rectangle rectangle) { double area = Double.POSITIVE_INFINITY; int sel = -1; for(int i = 0; i < usedSpace; i ++) { double enlargement = datas[i].getUnionRectangle(rectangle).getArea() - datas[i].getArea(); if(enlargement < area) { area = enlargement; sel = i; }else if(enlargement == area) { sel = (datas[sel].getArea() < datas[i].getArea()) ? sel : i; } } return sel; } /** * 插入新的Rectangle后从插入的叶节点开始向上调整RTree,直到根节点 * @param node1 引起需要调整的孩子结点 * @param node2 分裂的结点,若未分裂则为null */ public void adjustTree(RTNode node1, RTNode node2) { //先要找到指向原来旧的结点(即未添加Rectangle之前)的条目的索引 datas[insertIndex] = node1.getNodeRectangle();//先用node1覆盖原来的结点 children.set(insertIndex, node1);//替换旧的结点 if(node2 != null) { insert(node2);//插入新的结点 }else if(! isRoot())//还没到达根节点 { RTDirNode parent = (RTDirNode) getParent(); parent.adjustTree(this, null);//向上调整直到根节点 } } /** * @param node * @return 如果结点需要分裂则返回true */ protected boolean insert(RTNode node) { if(usedSpace < rtree.getNodeCapacity()) { datas[usedSpace ++] = node.getNodeRectangle(); children.add(node);//新加的 node.parent = this;//新加的 RTDirNode parent = (RTDirNode) getParent(); if(parent != null) { parent.adjustTree(this, null); } return false; }else{//非叶子结点需要分裂 RTDirNode[] a = splitIndex(node); RTDirNode n = a[0]; RTDirNode nn = a[1]; if(isRoot()) { //新建根节点,层数加1 RTDirNode newRoot = new RTDirNode(rtree, Constants.NULL, level + 1); //还需要把原来结点的孩子添加到两个分裂的结点n和nn中,此时n和nn的孩子结点还为空 // for(int i = 0; i < n.usedSpace; i ++) // { // n.children.add(this.children.get(index)); // } // // for(int i = 0; i < nn.usedSpace; i ++) // { // nn.children.add(this.children.get(index)); // } //把两个分裂的结点n和nn添加到根节点 newRoot.addData(n.getNodeRectangle()); newRoot.addData(nn.getNodeRectangle()); newRoot.children.add(n); newRoot.children.add(nn); //设置两个分裂的结点n和nn的父节点 n.parent = newRoot; nn.parent = newRoot; //最后设置rtree的根节点 rtree.setRoot(newRoot);//新加的 }else { RTDirNode p = (RTDirNode) getParent(); p.adjustTree(n, nn); } } return true; } /** * 非叶子结点的分裂 * * @param node * @return */ private RTDirNode[] splitIndex(RTNode node) { int[][] group = null; switch (rtree.getTreeType()) { case Constants.RTREE_LINEAR: break; case Constants.RTREE_QUADRATIC: group = quadraticSplit(node.getNodeRectangle()); children.add(node);//新加的 node.parent = this;//新加的 break; case Constants.RTREE_EXPONENTIAL: break; case Constants.RSTAR: break; default: throw new IllegalStateException("Invalid tree type."); } RTDirNode index1 = new RTDirNode(rtree, parent, level); RTDirNode index2 = new RTDirNode(rtree, parent, level); int[] group1 = group[0]; int[] group2 = group[1]; for(int i = 0; i < group1.length; i ++) { //为index1添加数据和孩子 index1.addData(datas[group1[i]]); index1.children.add(this.children.get(group1[i]));//新加的 //让index1成为其父节点 this.children.get(group1[i]).parent = index1;//新加的 } for(int i = 0; i < group2.length; i ++) { index2.addData(datas[group2[i]]); index2.children.add(this.children.get(group2[i]));//新加的 this.children.get(group2[i]).parent = index2;//新加的 } return new RTDirNode[]{index1,index2}; } @Override protected RTDataNode findLeaf(Rectangle rectangle) { for(int i = 0; i < usedSpace; i ++) { if(datas[i].enclosure(rectangle)) { deleteIndex = i;//记录搜索路径 RTDataNode leaf = children.get(i).findLeaf(rectangle); if(leaf != null) return leaf; } } return null; } } package com.njupt.rtree; /** * 外包矩形 * @ClassName Rectangle * @Description */ public class Rectangle implements Cloneable { private Point low; private Point high; public Rectangle(Point p1, Point p2) { if(p1 == null || p2 == null) { throw new IllegalArgumentException("Points cannot be null."); } if(p1.getDimension() != p2.getDimension()) { throw new IllegalArgumentException("Points must be of same dimension."); } //先左下角后右上角 for(int i = 0; i < p1.getDimension(); i ++) { if(p1.getFloatCoordinate(i) > p2.getFloatCoordinate(i)) { throw new IllegalArgumentException("坐标点为先左下角后右上角"); } } low = (Point) p1.clone(); high = (Point) p2.clone(); } /** * 返回Rectangle左下角的Point * @return Point */ public Point getLow() { return (Point) low.clone(); } /** * 返回Rectangle右上角的Point * @return Point */ public Point getHigh() { return high; } /** * @param rectangle * @return 包围两个Rectangle的最小Rectangle */ public Rectangle getUnionRectangle(Rectangle rectangle) { if(rectangle == null) throw new IllegalArgumentException("Rectangle cannot be null."); if(rectangle.getDimension() != getDimension()) { throw new IllegalArgumentException("Rectangle must be of same dimension."); } float[] min = new float[getDimension()]; float[] max = new float[getDimension()]; for(int i = 0; i < getDimension(); i ++) { min[i] = Math.min(low.getFloatCoordinate(i), rectangle.low.getFloatCoordinate(i)); max[i] = Math.max(high.getFloatCoordinate(i), rectangle.high.getFloatCoordinate(i)); } return new Rectangle(new Point(min), new Point(max)); } /** * @return 返回Rectangle的面积 */ public float getArea() { float area = 1; for(int i = 0; i < getDimension(); i ++) { area *= high.getFloatCoordinate(i) - low.getFloatCoordinate(i); } return area; } /** * @param rectangles * @return 包围一系列Rectangle的最小Rectangle */ public static Rectangle getUnionRectangle(Rectangle[] rectangles) { if(rectangles == null || rectangles.length == 0) throw new IllegalArgumentException("Rectangle array is empty."); Rectangle r0 = (Rectangle) rectangles[0].clone(); for(int i = 1; i < rectangles.length; i ++) { r0 = r0.getUnionRectangle(rectangles[i]); } return r0; } @Override protected Object clone() { Point p1 = (Point) low.clone(); Point p2 = (Point) high.clone(); return new Rectangle(p1, p2); } @Override public String toString() { return "Rectangle Low:" + low + " High:" + high; } public static void main(String[] args) { float[] f1 = {1.3f,2.4f}; float[] f2 = {3.4f,4.5f}; Point p1 = new Point(f1); Point p2 = new Point(f2); Rectangle rectangle = new Rectangle(p1, p2); System.out.println(rectangle); // Point point = rectangle.getHigh(); // point = p1; // System.out.println(rectangle); float[] f_1 = {0f,0f}; float[] f_2 = {-2f,2f}; float[] f_3 = {3f,3f}; float[] f_4 = {2.5f,2.5f}; float[] f_5 = {1.5f,1.5f}; p1 = new Point(f_1); p2 = new Point(f_2); Point p3 = new Point(f_3); Point p4 = new Point(f_4); Point p5 = new Point(f_5); Rectangle re1 = new Rectangle(p1, p2); Rectangle re2 = new Rectangle(p2, p3); Rectangle re3 = new Rectangle(p4, p3); // Rectangle re4 = new Rectangle(p3, p4); Rectangle re5 = new Rectangle(p5, p4); System.out.println(re1.isIntersection(re2)); System.out.println(re1.isIntersection(re3)); System.out.println(re1.intersectingArea(re2)); System.out.println(re1.intersectingArea(re5)); } /** * 两个Rectangle相交的面积 * @param rectangle Rectangle * @return float */ public float intersectingArea(Rectangle rectangle) { if(! isIntersection(rectangle)) { return 0; } float ret = 1; for(int i = 0; i < rectangle.getDimension(); i ++) { float l1 = this.low.getFloatCoordinate(i); float h1 = this.high.getFloatCoordinate(i); float l2 = rectangle.low.getFloatCoordinate(i); float h2 = rectangle.high.getFloatCoordinate(i); //rectangle1在rectangle2的左边 if(l1 <= l2 && h1 <= h2) { ret *= (h1 - l1) - (l2 - l1); }else if(l1 >= l2 && h1 >= h2) //rectangle1在rectangle2的右边 { ret *= (h2 - l2) - (l1 - l2); }else if(l1 >= l2 && h1 <= h2) //rectangle1在rectangle2里面 { ret *= h1 - l1; }else if(l1 <= l2 && h1 >= h2) //rectangle1包含rectangle2 { ret *= h2 - l2; } } return ret; } /** * @param rectangle * @return 判断两个Rectangle是否相交 */ public boolean isIntersection(Rectangle rectangle) { if(rectangle == null) throw new IllegalArgumentException("Rectangle cannot be null."); if(rectangle.getDimension() != getDimension()) { throw new IllegalArgumentException("Rectangle cannot be null."); } for(int i = 0; i < getDimension(); i ++) { if(low.getFloatCoordinate(i) > rectangle.high.getFloatCoordinate(i) || high.getFloatCoordinate(i) < rectangle.low.getFloatCoordinate(i)) { return false; } } return true; } /** * @return 返回Rectangle的维度 */ private int getDimension() { return low.getDimension(); } /** * 判断rectangle是否被包围 * @param rectangle * @return */ public boolean enclosure(Rectangle rectangle) { if(rectangle == null) throw new IllegalArgumentException("Rectangle cannot be null."); if(rectangle.getDimension() != getDimension()) throw new IllegalArgumentException("Rectangle dimension is different from current dimension."); for(int i = 0; i < getDimension(); i ++) { if(rectangle.low.getFloatCoordinate(i) < low.getFloatCoordinate(i) || rectangle.high.getFloatCoordinate(i) > high.getFloatCoordinate(i)) return false; } return true; } @Override public boolean equals(Object obj) { if(obj instanceof Rectangle) { Rectangle rectangle = (Rectangle) obj; if(low.equals(rectangle.getLow()) && high.equals(rectangle.getHigh())) return true; } return false; } } package com.njupt.constants; import com.njupt.rtree.RTNode; public class Constants { public static final int MAX_NUMBER_OF_ENTRIES_IN_NODE = 20;//结点中的最大条目数 public static final int MIN_NUMBER_OF_ENTRIES_IN_NODE = 8;//结点中的最小条目数 public static final int RTDataNode_Dimension = 2; /** Available RTree variants. */ public static final int RTREE_LINEAR = 0; public static final int RTREE_QUADRATIC = 1; public static final int RTREE_EXPONENTIAL = 2; public static final int RSTAR = 3; public static final int NIL = -1; public static final RTNode NULL = null; } package com.njupt.rtree; /** * @ClassName Point * @Description n维空间中的点,所有的维度被存储在一个float数组中 */ public class Point implements Cloneable { private float[] data; public Point(float[] data) { if(data == null) { throw new IllegalArgumentException("Coordinates cannot be null."); } if(data.length < 2) { throw new IllegalArgumentException("Point dimension should be greater than 1."); } this.data = new float[data.length]; System.arraycopy(data, 0, this.data, 0, data.length); } public Point(int[] data) { if(data == null) { throw new IllegalArgumentException("Coordinates cannot be null."); } if(data.length < 2) { throw new IllegalArgumentException("Point dimension should be greater than 1."); } this.data = new float[data.length]; for(int i = 0 ; i < data.length ; i ++) { this.data[i] = data[i]; } } @Override protected Object clone() { float[] copy = new float[data.length]; System.arraycopy(data, 0, copy, 0, data.length); return new Point(copy); } @Override public String toString() { StringBuffer sBuffer = new StringBuffer("("); for(int i = 0 ; i < data.length - 1 ; i ++) { sBuffer.append(data[i]).append(","); } sBuffer.append(data[data.length - 1]).append(")"); return sBuffer.toString(); } public static void main(String[] args) { float[] test = {1.2f,2f,34f}; Point point1 = new Point(test); System.out.println(point1); int[] test2 = {1,2,3,4}; point1 = new Point(test2); System.out.println(point1); } /** * @return 返回Point的维度 */ public int getDimension() { return data.length; } /** * @param index * @return 返回Point坐标第i位的float值 */ public float getFloatCoordinate(int index) { return data[index]; } /** * @param index * @return 返回Point坐标第i位的int值 */ public int getIntCoordinate(int index) { return (int) data[index]; } @Override public boolean equals(Object obj) { if(obj instanceof Point) { Point point = (Point) obj; if(point.getDimension() != getDimension()) throw new IllegalArgumentException("Points must be of equal dimensions to be compared."); for(int i = 0; i < getDimension(); i ++) { if(getFloatCoordinate(i) != point.getFloatCoordinate(i)) return false; } } if(! (obj instanceof Point)) return false; return true; } } 原博客请看链接 > https://blog.csdn.net/renyisheng/article/details/40347223


你可能感兴趣的:(R树的Java实现)