📄 tree.java
字号:
/*
* Tree.java
* Copyright (C) 1999 dog <dog@dog.net.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* You may retrieve the latest version of this library from
* http://www.dog.net.uk/knife/
*/
package dog.util;
import java.util.Vector;
/**
* A utility class for manipulating objects in a tree structure.
* <p>
* This class provides a way to associate arbitrary objects with one another in a hierarchy.
*
* @author dog@dog.net.uk
* @version 1.0
*/
public final class Tree {
int nparents = 0;
Object[] parents;
int[] nchildren;
Object[][] children;
int nelements = 0;
Object[] elements;
int[] depths;
int increment;
Object LOCK = new Object();
/**
* Constructs an empty tree.
*/
public Tree() {
this(10);
}
/**
* Constructs an empty tree with the specified capacity increment.
* @param increment the amount by which the capacity is increased when an array overflows.
*/
public Tree(int increment) {
super();
this.increment = (increment>0) ? increment : 1;
clear();
}
// Returns the elements index of the specified object, or -1 if no such element exists.
private int elementIndex(Object object) {
for (int i=0; i<nelements; i++)
if (elements[i]==object)
return i;
return -1;
}
// Returns the parents index of the specified object, or -1 if no such parent exists.
private int parentIndex(Object object) {
for (int i=0; i<nparents; i++)
if (parents[i]==object)
return i;
return -1;
}
/**
* Returns the parent of the specified object,
* or null if the object is a root or not a child in the tree.
*/
public Object getParent(Object child) {
synchronized (LOCK) {
return parentOf(child);
}
}
private Object parentOf(Object child) {
for (int p = 0; p<nparents; p++) {
for (int c = 0; c<nchildren[p]; c++)
if (children[p][c]==child)
return parents[p];
}
return null;
}
/**
* Returns an array of children of the specified object,
* or an empty array if the object is not a parent in the tree.
*/
public Object[] getChildren(Object parent) {
synchronized (LOCK) {
int p = parentIndex(parent);
if (p>-1) {
Object[] c = new Object[nchildren[p]];
System.arraycopy(children[p], 0, c, 0, nchildren[p]);
return c;
}
}
return new Object[0];
}
/**
* Returns the number of children of the specified object.
*/
public int getChildCount(Object parent) {
synchronized (LOCK) {
int p = parentIndex(parent);
if (p>-1)
return nchildren[p];
}
return 0;
}
/**
* Indicates whether the specified object is contained in the tree.
*/
public boolean contains(Object object) {
synchronized (LOCK) {
return (elementIndex(object)>-1);
}
}
private void ensureRootCapacity(int amount) {
// calculate the amount by which to increase arrays
int block = ((int)(Math.max(Math.ceil((double)amount/(double)increment), 1)))*increment;
// ensure capacity of elements
if (elements.length<nelements+amount) {
int len = elements.length;
Object[] newelements = new Object[len+block];
System.arraycopy(elements, 0, newelements, 0, nelements);
elements = newelements;
int[] newdepths = new int[len+block];
System.arraycopy(depths, 0, newdepths, 0, nelements);
depths = newdepths;
}
}
private void ensureParentCapacity(int amount) {
// calculate the amount by which to increase arrays
int block = ((int)(Math.max(Math.ceil((double)amount/(double)increment), 1)))*increment;
// ensure capacity of parents (and hence children in parent dimension)
if (parents.length<nparents+1) {
Object[] newparents = new Object[parents.length+increment];
System.arraycopy(parents, 0, newparents, 0, nparents);
parents = newparents;
Object[][] newchildren = new Object[parents.length+increment][];
System.arraycopy(children, 0, newchildren, 0, nparents);
children = newchildren;
int[] newnchildren = new int[parents.length+increment];
System.arraycopy(nchildren, 0, newnchildren, 0, nparents);
nchildren = newnchildren;
}
// ensure capacity of elements
if (elements.length<nelements+amount) {
int len = elements.length;
Object[] newelements = new Object[len+block];
System.arraycopy(elements, 0, newelements, 0, nelements);
elements = newelements;
int[] newdepths = new int[len+block];
System.arraycopy(depths, 0, newdepths, 0, nelements);
depths = newdepths;
}
}
private void ensureChildCapacity(int amount, int parent) {
// calculate the amount by which to increase arrays
int block = ((int)(Math.max(Math.ceil((double)amount/(double)increment), 1)))*increment;
// ensure capacity of children for this parent
if (children[parent].length<nchildren[parent]+amount) {
Object[] newchildren = new Object[children[parent].length+block];
System.arraycopy(children[parent], 0, newchildren, 0, nchildren[parent]);
children[parent] = newchildren;
}
// ensure capacity of elements
if (elements.length<nelements+amount) {
int len = elements.length;
Object[] newelements = new Object[len+block];
System.arraycopy(elements, 0, newelements, 0, nelements);
elements = newelements;
int[] newdepths = new int[len+block];
System.arraycopy(depths, 0, newdepths, 0, nelements);
depths = newdepths;
}
}
/**
* Adds a root to the tree.
* Returns the root if it was added.
*/
public void add(Object object) {
if (object==null)
throw new NullPointerException("cannot add null to a tree");
synchronized (LOCK) {
int e;
if ((e = elementIndex(object))>-1) // if we already have the object
removeElement(e); // remove it
ensureRootCapacity(1);
elements[nelements] = object;
depths[nelements] = 1;
nelements++;
}
}
/**
* Adds roots to the tree.
*/
public void add(Object[] objects) {
synchronized (LOCK) {
for (int i=0; i<objects.length; i++) {
if (objects[i]==null)
throw new NullPointerException("cannot add null to a tree");
int e;
if ((e = elementIndex(objects[i]))>-1) // if we already have the object
removeElement(e); // remove it
}
ensureRootCapacity(objects.length);
System.arraycopy(objects, 0, elements, nelements, objects.length);
for (int i=nelements; i<nelements+objects.length; i++)
depths[i] = 1;
nelements += objects.length;
}
}
/**
* Adds a child to the specified parent in the tree.
* @throws IllegalArgumentException if the parent does not exist in the tree or the child is the parent.
*/
public void add(Object parent, Object child) {
if (parent==null)
throw new NullPointerException("null parent specified");
if (child==null)
throw new NullPointerException("cannot add null to a tree");
if (child==parent)
throw new IllegalArgumentException("cannot add child to itself");
synchronized (LOCK) {
int p = parentIndex(parent), pe = -1;
if (p<0) { // does it exist in the tree?
if ((pe = elementIndex(parent))<0)
throw new IllegalArgumentException("parent does not exist");
} // so we'll add it to parents
int e;
if ((e = elementIndex(child))>-1) // if the child is already an element
removeElement(e);
if (p<0) { // add the parent to parents
p = nparents;
ensureParentCapacity(1);
parents[p] = parent;
children[p] = new Object[increment];
nchildren[p] = 0;
nparents++;
}
ensureChildCapacity(1, p);
children[p][nchildren[p]] = child;
// insert the child into elements and set its depth
int depth = depth(parent);
int off = pe+nchildren[p]+1;
int len = nelements-off;
Object[] buffer = new Object[len];
System.arraycopy(elements, off, buffer, 0, len);
elements[off] = child;
System.arraycopy(buffer, 0, elements, off+1, len);
int[] dbuffer = new int[len];
System.arraycopy(depths, off, dbuffer, 0, len);
depths[off] = depth+1;
System.arraycopy(dbuffer, 0, depths, off+1, len);
nelements++;
nchildren[p]++;
}
}
/**
* Adds children to the specified parent in the tree.
* @throws IllegalArgumentException if the parent does not exist in the tree or one of the children is the parent.
*/
public void add(Object parent, Object[] children) {
if (parent==null)
throw new NullPointerException("null parent specified");
synchronized (LOCK) {
int p = parentIndex(parent), pe = -1;
if (p<0) { // does it exist in the tree?
if ((pe = elementIndex(parent))<0)
throw new IllegalArgumentException("parent does not exist");
} // so we'll add it to parents
for (int i=0; i<children.length; i++) {
if (children[i]==null)
throw new NullPointerException("cannot add null to a tree");
if (children[i]==parent)
throw new IllegalArgumentException("cannot add child to itself");
int e;
if ((e = elementIndex(children[i]))>-1) // if we already have the object
removeElement(e); // remove it
}
if (p<0) { // add the parent to parents
p = nparents;
ensureParentCapacity(1);
parents[p] = parent;
this.children[p] = new Object[Math.max(increment, (children.length/increment)*increment)];
nchildren[p] = 0;
nparents++;
}
ensureChildCapacity(children.length, p);
System.arraycopy(children, 0, this.children[p], nchildren[p], children.length);
// insert the children into elements and set their depths
int depth = depth(parent);
int off = pe+nchildren[p]+1;
int len = nelements-off;
Object[] buffer = new Object[len];
System.arraycopy(elements, off, buffer, 0, len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -