我已经使用"median of list"算法编写了Java中的KD树,用于构建更平衡的树。在使用维基提供的数据时,它似乎工作正常,请注意维基百科示例仅使用X,Y值,因此它不会评估Z深度。KD-Tree“列表中位数”构建
维基百科:
point_list = [(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)]
depth=0 id=(7.0, 2.0, 0.0)
├── [left] depth=1 id=(5.0, 4.0, 0.0)
│ ├── [left] depth=2 id=(2.0, 3.0, 0.0)
│ └── [right] depth=2 id=(4.0, 7.0, 0.0)
└── [right] depth=1 id=(9.0, 6.0, 0.0)
└── [left] depth=2 id=(8.0, 1.0, 0.0)
但是,当我使用的方法 “列表中位数” 这个数据,它似乎并没有好好工作。
point list = [(1,0,-1), (1,0,-2), (1,0,1), (1,0,2)]
我得到一棵树是这样的:
depth=0 id=(1.0, 0.0, 1.0)
├── [left] depth=1 id=(1.0, 0.0, -2.0)
│ └── [left] depth=2 id=(1.0, 0.0, -1.0)
└── [right] depth=1 id=(1.0, 0.0, 2.0)
看起来并不正确,因为(1.0,0.0,2.0)是右边(1.0,0.0,1.0),但它们是基本上相等,因为它们的Y值相等。此外,(1.0,0.0,-1.0)在(1.0,0.0,-2.0)的左边,它应该在右边,因为它的Z值更大。
我认为问题源于具有相等的X和Y值以及只有变量Z值,因此列表的中位数并不能准确地分割列表。
...原代码以下wiki的Python代码...
private static KdNode createNode(List<XYZPoint> list, int k, int depth) {
if (list == null || list.size() == 0) return null;
int axis = depth % k;
if (axis == X_AXIS) Collections.sort(list, X_COMPARATOR);
else if (axis == Y_AXIS) Collections.sort(list, Y_COMPARATOR);
else Collections.sort(list, Z_COMPARATOR);
KdNode node = null;
if (list.size() > 0) {
int mediaIndex = list.size()/2;
node = new KdNode(k, depth, list.get(mediaIndex));
if ((mediaIndex - 1) >= 0) {
List<XYZPoint> less = list.subList(0, mediaIndex);
if (less.size() > 0) {
node.lesser = createNode(less, k, depth + 1);
node.lesser.parent = node;
}
}
if ((mediaIndex + 1) <= (list.size() - 1)) {
List<XYZPoint> more = list.subList(mediaIndex + 1, list.size());
if (more.size() > 0) {
node.greater = createNode(more, k, depth + 1);
node.greater.parent = node;
}
}
}
return node;
}
...根据我的意见的新代码...
private static KdNode createNode(List<XYZPoint> list, int k, int depth) {
if (list == null || list.size() == 0) return null;
int axis = depth % k;
if (axis == X_AXIS) Collections.sort(list, X_COMPARATOR);
else if (axis == Y_AXIS) Collections.sort(list, Y_COMPARATOR);
else Collections.sort(list, Z_COMPARATOR);
KdNode node = null;
if (list.size() > 0) {
int medianIndex = list.size()/2;
node = new KdNode(k, depth, list.get(medianIndex));
List<XYZPoint> less = new ArrayList<XYZPoint>(list.size()-1);
List<XYZPoint> more = new ArrayList<XYZPoint>(list.size()-1);
//Process list to see where each non-median point lies
for (int i=0; i<list.size(); i++) {
if (i==medianIndex) continue;
XYZPoint p = list.get(i);
if (KdNode.compareTo(depth, k, p, node.id)<=0) {
less.add(p);
} else {
more.add(p);
}
}
if (less.size() > 0) {
node.lesser = createNode(less, k, depth + 1);
node.lesser.parent = node;
}
if (more.size() > 0) {
node.greater = createNode(more, k, depth + 1);
node.greater.parent = node;
}
}
这似乎是在我选择中位数后,我将不得不处理列表以查看每个点与中位数的关系。这不会创建KD-Tree一个n *((n log n)+(n))进程吗? (n log n)对列表进行排序,(n)查看每个元素与中位数的关系。 – Justin