数据布局第30节 空间划分树

打印 上一主题 下一主题

主题 992|帖子 992|积分 2976

空间划分树是一种数据布局,主要用于多维空间中数据的组织和查询,尤其实用于需要频繁举行范围查询或相近性查询的场景,如盘算机图形学、地理信息系统、物理学模仿和数据库索引等。空间划分树通过递归地将空间分割成更小的区域,从而有效地减少搜刮范围,提高查询服从。
常见的空间划分树


  • 四叉树(Quadtree)

    • 用于二维空间。
    • 每个内部节点有四个子节点,对应其空间区域的四个象限。
    • 当一个区域内的数据点数超过阈值或达到一定深度时,该区域被分割成四个子区域。

  • 八叉树(Octree)

    • 用于三维空间。
    • 每个内部节点有八个子节点,对应其空间区域的八个子立方体。
    • 分割规则与四叉树雷同,但应用于三维空间。

  • k-d树(k-dimensional tree)

    • 可用于任意维度的空间。
    • 每个节点在其中一个维度上举行划分,瓜代地在差别维度上举行切割。
    • 子节点表示沿该维度切割后的两个子空间。

  • R树(R-tree)

    • 专为多维空间计划的索引布局,用于解决矩形范围查询。
    • 使用最小外接矩形(MBR)来包围一组点或另一个R树的节点。
    • 支持动态插入和删除操纵。

  • R*树(R-star tree)

    • R树的改进版,优化了节点的重分布和合并策略,以减少重叠和提高查询服从。

  • BSP树(Binary Space Partitioning Tree)

    • 通过一系列超平面(在二维中是线,在三维中是平面)将空间分割成两半。
    • 通常用于盘算机图形学中的可见性测试和光线追踪。

  • BVH树(Bounding Volume Hierarchy)

    • 与BSP树雷同,但使用简单的界限体(如球体或轴对齐的包围盒)来包围空间区域。
    • 用于加快碰撞检测和光线追踪算法。

空间划分树的构建

构建空间划分树通常遵照以下步骤:

  • 初始化:创建一个根节点,代表整个空间区域。
  • 插入元素:对于每个要插入的元素,确定其所属的子区域,并递归地插入到相应的子节点中。
  • 节点分割:当一个节点包含的元素数目超过预界说的阈值或达到特定深度时,该节点被分割成多个子节点。
  • 平衡:在某些情况下,如R树和R*树,需要保持树的平衡,制止某些节点过于拥挤而其他节点几乎为空。
查询

空间划分树支持多种查询,包罗但不限于:


  • 范围查询:找出落在给定区域内的所有元素。
  • 最近邻查询:找出离给定点最近的元素。
  • k最近邻查询:找出离给定点最近的k个元素。
  • 碰撞检测:检测空间中两个或多个人或物体之间的潜在碰撞。
空间划分树可以或许明显提高多维数据查询的速度,尤其是在大数据集上。然而,它们也有缺点,如在数据分布不均时大概会导致不平衡,从而影响性能。因此,选择合适的数据布局和参数设置对于得到最佳性能至关紧张。
在Java中实现四叉树和八叉树,你需要界说基本的节点类以及树本身。下面我将分别给出四叉树和八叉树的简化版代码实现示例。
四叉树实现

  1. public class QuadTree {
  2.     private static final int MAX_OBJECTS = 4; // 最大对象数
  3.     private static final int MAX_LEVELS = 5; // 最大深度
  4.     private Node root;
  5.     private int levels;
  6.     public QuadTree() {
  7.         this.root = new Node(null, 0, 0, 100, 100);
  8.         this.levels = 0;
  9.     }
  10.     private class Node {
  11.         Rectangle bounds;
  12.         List<Object> objects;
  13.         Node[] nodes;
  14.         public Node(Node parent, int x, int y, int w, int h) {
  15.             bounds = new Rectangle(x, y, w, h);
  16.             objects = new ArrayList<>();
  17.             nodes = new Node[4];
  18.         }
  19.         private void subdivide() {
  20.             int subWidth = bounds.width / 2;
  21.             int subHeight = bounds.height / 2;
  22.             int x = bounds.x;
  23.             int y = bounds.y;
  24.             nodes[0] = new Node(this, x, y, subWidth, subHeight);
  25.             nodes[1] = new Node(this, x + subWidth, y, subWidth, subHeight);
  26.             nodes[2] = new Node(this, x, y + subHeight, subWidth, subHeight);
  27.             nodes[3] = new Node(this, x + subWidth, y + subHeight, subWidth, subHeight);
  28.         }
  29.         public boolean insert(Object obj) {
  30.             // 省略具体的插入逻辑...
  31.         }
  32.     }
  33.     public void insert(Object obj) {
  34.         if (root.objects.size() < MAX_OBJECTS && levels < MAX_LEVELS) {
  35.             root.insert(obj);
  36.         } else {
  37.             // 处理超出容量的情况...
  38.         }
  39.     }
  40. }
复制代码
八叉树实现

  1. public class Octree {
  2.     private static final int MAX_OBJECTS = 8;
  3.     private static final int MAX_LEVELS = 5;
  4.     private Node root;
  5.     private int levels;
  6.     public Octree() {
  7.         this.root = new Node(null, new Vector3f(0, 0, 0), 100);
  8.         this.levels = 0;
  9.     }
  10.     private class Node {
  11.         Box bounds;
  12.         List<Object> objects;
  13.         Node[] nodes;
  14.         public Node(Node parent, Vector3f center, float size) {
  15.             bounds = new Box(center, size);
  16.             objects = new ArrayList<>();
  17.             nodes = new Node[8];
  18.         }
  19.         private void subdivide() {
  20.             // 省略具体细分逻辑...
  21.         }
  22.         public boolean insert(Object obj) {
  23.             // 省略具体的插入逻辑...
  24.         }
  25.     }
  26.     public void insert(Object obj) {
  27.         if (root.objects.size() < MAX_OBJECTS && levels < MAX_LEVELS) {
  28.             root.insert(obj);
  29.         } else {
  30.             // 处理超出容量的情况...
  31.         }
  32.     }
  33. }
复制代码
留意,上述代码是高度简化的,现实应用中,insert方法会更复杂,需要检查对象是否在节点的界限内,假如节点已满,则需要细分节点,等等。此外,Node类中的objects列表将根据你的具体需求存储特定范例的数据,比方坐标点、游戏对象等。同时,你还需要实现subdivide方法,用于将节点分割成更小的子节点。
在实现四叉树和八叉树时,确保考虑到界限条件,比方当树的深度达到预设的最大值时应该做什么,以及怎样处理对象的删除操纵。
在Java中实现四叉树和八叉树,你需要界说基本的节点类以及树本身。下面我将分别给出四叉树和八叉树的简化版代码实现示例。
四叉树实现

  1. public class QuadTree {
  2.     private static final int MAX_OBJECTS = 4; // 最大对象数
  3.     private static final int MAX_LEVELS = 5; // 最大深度
  4.     private Node root;
  5.     private int levels;
  6.     public QuadTree() {
  7.         this.root = new Node(null, 0, 0, 100, 100);
  8.         this.levels = 0;
  9.     }
  10.     private class Node {
  11.         Rectangle bounds;
  12.         List<Object> objects;
  13.         Node[] nodes;
  14.         public Node(Node parent, int x, int y, int w, int h) {
  15.             bounds = new Rectangle(x, y, w, h);
  16.             objects = new ArrayList<>();
  17.             nodes = new Node[4];
  18.         }
  19.         private void subdivide() {
  20.             int subWidth = bounds.width / 2;
  21.             int subHeight = bounds.height / 2;
  22.             int x = bounds.x;
  23.             int y = bounds.y;
  24.             nodes[0] = new Node(this, x, y, subWidth, subHeight);
  25.             nodes[1] = new Node(this, x + subWidth, y, subWidth, subHeight);
  26.             nodes[2] = new Node(this, x, y + subHeight, subWidth, subHeight);
  27.             nodes[3] = new Node(this, x + subWidth, y + subHeight, subWidth, subHeight);
  28.         }
  29.         public boolean insert(Object obj) {
  30.             // 省略具体的插入逻辑...
  31.         }
  32.     }
  33.     public void insert(Object obj) {
  34.         if (root.objects.size() < MAX_OBJECTS && levels < MAX_LEVELS) {
  35.             root.insert(obj);
  36.         } else {
  37.             // 处理超出容量的情况...
  38.         }
  39.     }
  40. }
复制代码
八叉树实现

  1. public class Octree {
  2.     private static final int MAX_OBJECTS = 8;
  3.     private static final int MAX_LEVELS = 5;
  4.     private Node root;
  5.     private int levels;
  6.     public Octree() {
  7.         this.root = new Node(null, new Vector3f(0, 0, 0), 100);
  8.         this.levels = 0;
  9.     }
  10.     private class Node {
  11.         Box bounds;
  12.         List<Object> objects;
  13.         Node[] nodes;
  14.         public Node(Node parent, Vector3f center, float size) {
  15.             bounds = new Box(center, size);
  16.             objects = new ArrayList<>();
  17.             nodes = new Node[8];
  18.         }
  19.         private void subdivide() {
  20.             // 省略具体细分逻辑...
  21.         }
  22.         public boolean insert(Object obj) {
  23.             // 省略具体的插入逻辑...
  24.         }
  25.     }
  26.     public void insert(Object obj) {
  27.         if (root.objects.size() < MAX_OBJECTS && levels < MAX_LEVELS) {
  28.             root.insert(obj);
  29.         } else {
  30.             // 处理超出容量的情况...
  31.         }
  32.     }
  33. }
复制代码
留意,上述代码是高度简化的,现实应用中,insert方法会更复杂,需要检查对象是否在节点的界限内,假如节点已满,则需要细分节点,等等。此外,Node类中的objects列表将根据你的具体需求存储特定范例的数据,比方坐标点、游戏对象等。同时,你还需要实现subdivide方法,用于将节点分割成更小的子节点。
在实现四叉树和八叉树时,确保考虑到界限条件,比方当树的深度达到预设的最大值时应该做什么,以及怎样处理对象的删除操纵。
这一次,我们将添加一些关键的逻辑,包罗插入、细分和查找方法。请留意,这里的代码仍然是示例性的,你大概需要根据你的具体应用举行调整。
四叉树完备实现

  1. import java.awt.Rectangle;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class QuadTree {
  5.     private static final int MAX_OBJECTS = 4;
  6.     private static final int MAX_LEVELS = 5;
  7.     private Node root;
  8.     private int levels;
  9.     public QuadTree(int x, int y, int width, int height) {
  10.         root = new Node(null, x, y, width, height);
  11.         levels = 0;
  12.     }
  13.     private class Node {
  14.         Rectangle bounds;
  15.         List<Object> objects;
  16.         Node[] nodes;
  17.         public Node(Node parent, int x, int y, int width, int height) {
  18.             bounds = new Rectangle(x, y, width, height);
  19.             objects = new ArrayList<>();
  20.             nodes = new Node[4];
  21.         }
  22.         public boolean insert(Object obj) {
  23.             if (nodes[0] != null) {
  24.                 // 如果有子节点,尝试将对象插入子节点
  25.                 for (int i = 0; i < 4; i++) {
  26.                     if (nodes[i].bounds.contains(obj.getPosition())) {
  27.                         return nodes[i].insert(obj);
  28.                     }
  29.                 }
  30.             }
  31.             // 如果没有子节点或者对象不在任何子节点中,就插入当前节点
  32.             objects.add(obj);
  33.             // 如果当前节点的对象数量超过最大值,且深度未达到最大值,则细分
  34.             if (objects.size() > MAX_OBJECTS && levels < MAX_LEVELS) {
  35.                 subdivide();
  36.                 // 将所有对象重新分配到子节点
  37.                 for (Object o : objects) {
  38.                     insert(o);
  39.                 }
  40.                 objects.clear();
  41.             }
  42.             return true;
  43.         }
  44.         private void subdivide() {
  45.             int subWidth = bounds.width / 2;
  46.             int subHeight = bounds.height / 2;
  47.             int x = bounds.x;
  48.             int y = bounds.y;
  49.             for (int i = 0; i < 4; i++) {
  50.                 nodes[i] = new Node(this, x, y, subWidth, subHeight);
  51.                 if (i == 1) x += subWidth;
  52.                 if (i == 2 || i == 3) {
  53.                     y += subHeight;
  54.                     x = bounds.x;
  55.                     if (i == 3) x += subWidth;
  56.                 }
  57.             }
  58.             levels++;
  59.         }
  60.     }
  61.     public boolean insert(Object obj) {
  62.         return root.insert(obj);
  63.     }
  64. }
复制代码
八叉树完备实现

  1. import org.joml.Vector3f;
  2. // 假设Box是一个三维矩形类
  3. class Box {
  4.     public Vector3f center;
  5.     public float size;
  6.     public Box(Vector3f center, float size) {
  7.         this.center = center;
  8.         this.size = size;
  9.     }
  10. }
  11. public class Octree {
  12.     private static final int MAX_OBJECTS = 8;
  13.     private static final int MAX_LEVELS = 5;
  14.     private Node root;
  15.     private int levels;
  16.     public Octree(Vector3f center, float size) {
  17.         root = new Node(null, center, size);
  18.         levels = 0;
  19.     }
  20.     private class Node {
  21.         Box bounds;
  22.         List<Object> objects;
  23.         Node[] nodes;
  24.         public Node(Node parent, Vector3f center, float size) {
  25.             bounds = new Box(center, size);
  26.             objects = new ArrayList<>();
  27.             nodes = new Node[8];
  28.         }
  29.         public boolean insert(Object obj) {
  30.             // 插入逻辑与四叉树类似,但需要考虑三维空间
  31.             if (nodes[0] != null) {
  32.                 for (int i = 0; i < 8; i++) {
  33.                     if (nodes[i].bounds.contains(obj.getPosition())) {
  34.                         return nodes[i].insert(obj);
  35.                     }
  36.                 }
  37.             }
  38.             objects.add(obj);
  39.             if (objects.size() > MAX_OBJECTS && levels < MAX_LEVELS) {
  40.                 subdivide();
  41.                 for (Object o : objects) {
  42.                     insert(o);
  43.                 }
  44.                 objects.clear();
  45.             }
  46.             return true;
  47.         }
  48.         private void subdivide() {
  49.             // 三维空间细分逻辑
  50.             // 略...
  51.         }
  52.     }
  53.     public boolean insert(Object obj) {
  54.         return root.insert(obj);
  55.     }
  56. }
复制代码
这里我们展示了怎样在四叉树和八叉树中插入对象,并在必要时对节点举行细分。为了完成这些类,你还需要实现subdivide方法中的细分逻辑,以及Box类的contains方法以判定对象是否在界限内。在八叉树的实现中,我们使用了org.joml.Vector3f类,假设你已经在项目中包含了JOML库。假如没有,你可以使用任何向量类来代替。
由于之前的代码片断中省略了一些关键部分,好比 subdivide 方法的具体实现和怎样检查一个对象是否在节点的界限内,我们现在将增补这部分代码。下面是更完备的四叉树和八叉树的实现。
完善四叉树

  1. import java.awt.Rectangle;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class QuadTree {
  5.     private static final int MAX_OBJECTS = 4;
  6.     private static final int MAX_LEVELS = 5;
  7.     private Node root;
  8.     private int levels;
  9.     public QuadTree(int x, int y, int width, int height) {
  10.         root = new Node(null, x, y, width, height);
  11.         levels = 0;
  12.     }
  13.     private class Node {
  14.         Rectangle bounds;
  15.         List<Object> objects;
  16.         Node[] nodes;
  17.         public Node(Node parent, int x, int y, int width, int height) {
  18.             bounds = new Rectangle(x, y, width, height);
  19.             objects = new ArrayList<>();
  20.             nodes = new Node[4];
  21.         }
  22.         public boolean insert(Object obj) {
  23.             if (nodes[0] != null) {
  24.                 // Try to insert the object into one of the children.
  25.                 for (int i = 0; i < 4; i++) {
  26.                     if (nodes[i].bounds.contains(obj.getPosition())) {
  27.                         return nodes[i].insert(obj);
  28.                     }
  29.                 }
  30.             }
  31.             // If no child node could be found, insert the object into this node.
  32.             objects.add(obj);
  33.             // If we've reached the max number of objects and the depth is less than the max level,
  34.             // subdivide this node and move all objects to their appropriate child nodes.
  35.             if (objects.size() > MAX_OBJECTS && levels < MAX_LEVELS) {
  36.                 subdivide();
  37.                 List<Object> tempObjects = new ArrayList<>(objects);
  38.                 objects.clear();
  39.                 for (Object o : tempObjects) {
  40.                     insert(o);
  41.                 }
  42.             }
  43.             return true;
  44.         }
  45.         private void subdivide() {
  46.             int subWidth = bounds.width / 2;
  47.             int subHeight = bounds.height / 2;
  48.             int x = bounds.x;
  49.             int y = bounds.y;
  50.             for (int i = 0; i < 4; i++) {
  51.                 nodes[i] = new Node(this, x, y, subWidth, subHeight);
  52.                 if (i == 1) x += subWidth;
  53.                 if (i == 2 || i == 3) {
  54.                     y += subHeight;
  55.                     x = bounds.x;
  56.                     if (i == 3) x += subWidth;
  57.                 }
  58.             }
  59.             levels++;
  60.         }
  61.     }
  62.     public boolean insert(Point2D obj) {
  63.         return root.insert(obj);
  64.     }
  65. }
复制代码
完善八叉树

  1. import org.joml.Vector3f;
  2. public class Octree {
  3.     private static final int MAX_OBJECTS = 8;
  4.     private static final int MAX_LEVELS = 5;
  5.     private Node root;
  6.     private int levels;
  7.     public Octree(Vector3f center, float size) {
  8.         root = new Node(null, center, size);
  9.         levels = 0;
  10.     }
  11.     private class Node {
  12.         Box bounds;
  13.         List<Object> objects;
  14.         Node[] nodes;
  15.         public Node(Node parent, Vector3f center, float size) {
  16.             bounds = new Box(center, size);
  17.             objects = new ArrayList<>();
  18.             nodes = new Node[8];
  19.         }
  20.         public boolean insert(Object obj) {
  21.             if (nodes[0] != null) {
  22.                 for (int i = 0; i < 8; i++) {
  23.                     if (nodes[i].bounds.contains(obj.getPosition())) {
  24.                         return nodes[i].insert(obj);
  25.                     }
  26.                 }
  27.             }
  28.             objects.add(obj);
  29.             if (objects.size() > MAX_OBJECTS && levels < MAX_LEVELS) {
  30.                 subdivide();
  31.                 List<Object> tempObjects = new ArrayList<>(objects);
  32.                 objects.clear();
  33.                 for (Object o : tempObjects) {
  34.                     insert(o);
  35.                 }
  36.             }
  37.             return true;
  38.         }
  39.         private void subdivide() {
  40.             float subSize = bounds.size / 2.0f;
  41.             Vector3f subCenter = new Vector3f();
  42.             for (int i = 0; i < 8; i++) {
  43.                 subCenter.set(bounds.center).add((i & 1) * subSize, ((i >> 1) & 1) * subSize, ((i >> 2) & 1) * subSize);
  44.                 nodes[i] = new Node(this, subCenter, subSize);
  45.             }
  46.             levels++;
  47.         }
  48.     }
  49.     public boolean insert(Point3D obj) {
  50.         return root.insert(obj);
  51.     }
  52. }
复制代码
在这个实现中,我们假设 Point2D 和 Point3D 类已经被界说,它们具有 getPosition() 方法返回位置信息,以便我们可以检查点是否位于节点的界限内。对于 Box 类,你需要自己实现它,包含必要的属性和方法,如 contains 方法,用来判定一个点是否在该三维盒子内。同样,Rectangle 类的 contains 方法将用于四叉树中的界限检查。
以上代码提供了一个基础框架,你可以根据自己的具体需求举行扩展和修改。比方,你大概需要添加删除和查找功能,以及处理界限条件和异常情况的代码。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

知者何南

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表