【问题标题】:Quadtree moving of stored points存储点的四叉树移动
【发布时间】:2012-10-01 07:27:42
【问题描述】:

我使用四叉树作为数据结构来存储点。因为我需要快速找到某个区域的所有点。

但是我需要移动点。在我的 C++ 程序中。由于移动发生在所有点上,但对于不同方向的每个点,我目前破坏了我的四叉树并重建它,这会导致大量分配和删除。

因此,我的问题是这种问题是否有更好的数据结构?

我有以下要求: 我有 n 点。

我需要快速获取给定特定区域的所有点。对于我的四叉树,这大约是 O(log(n))。然而,这个操作被称为 m 次,其中 m > n 因此它大约是 O(m*log(n))。

我需要移动所有点。目前,这大约运行 O(n*logn)。该方法只对所有 m 调用一次。

但是,我目前觉得这个解决方案不能令人满意。因为我总是破坏我的四叉树并重建它,这会由于分配而导致开销。

更新: 点不是均匀分布的。有密集的位置,也有点少的位置。

这是一些简化的代码。这里是存储的指针代码:

class Point
{
    public:
    Point(double x, double y):x(x),y(y){};

    void movePoint(double ux, double uy);

    double x;
    double y;
};

这里是四叉树的界面

class QuadTree
{
public:
    QuadTree(double north, double west, double south, double east,
             int maxItems);

    //inserts a point into the tree runs in log(n)
    bool put(Point* pt);
    // returns all point in the rectange defined by the four variables runs in log(n)
    std::vector<Point*> get(double north, double west, double south, double east);
    // deletes everything in the quad tree
    void clear();

private:

    QuadTreeNode* top_=nullptr;

};

这里是 QuadTreeNode 的接口与 get 和 put 方法的实现,以显示 Point 是如何存储的。

class QuadTreeNode
{
public:

    QuadTreeNode(double north, double west, double south, double east,
                 int maximumItems);

    ~QuadTreeNode();

    //split the node if to much items are stored.
    void split();
    //returns the children of the node
    QuadTreeNode* getChild(double x, double y);

    bool put(Point* leaf){
      if (children_ == nullptr) {
        items_.push_back(leaf);

        if (items_.size() > maxItems_)
            split();
        return true;
      } else {
        QuadTreeNode* node = getChild(leaf->getX(), leaf->getY());
        if (node != nullptr) {
            return node->put(leaf);
        }
       }
      return false;
    }

    std::vector<Point*> QuadTreeNode::get(QuadRectangle rect, std::vector<Point*>& vector) {
      if (children_ == nullptr) {
        for (Point* pt : items_) {
            if (rect.pointWithinBounds(pt->getX(),pt->getY())) {
                vector.push_back(pt);
            }
        }
      } else {
        for (QuadTreeNode* child : *children_) {
            if (child->bounds_.within(rect)) {
                child->get(rect, vector);
            }
        }
      }
      return vector;
}

    std::vector<Point*> items_;

    unsigned int maxItems_;

    std::array<QuadTreeNode*,4>* children_ = nullptr;

    QuadRectangle bounds_;    
};

【问题讨论】:

  • 请提供更多关于什么是四叉树的信息。也许一些代码sn-p。
  • 您可以重复使用之前分配的存储空间,避免分配。
  • 如果您的点几乎是同质的(接近均匀分布),那么最好使用简单的搜索网格(桶),使用坐标本身的位模式作为索引。
  • 我不确定如何,因为四叉树的结构可能完全不同。存储的点不会重新分配,但四叉树可能会。
  • 我认为 Walter 的意思(在他的第一篇文章中)是在可能的情况下通过重新链接节点指针来重新使用四叉树节点,并根据需要调整图形。您还可以维护未使用节点的“池”。实现其中任何一个都会增加一些复杂性,但如果您在重新分配方面遇到瓶颈,则可能值得。

标签: c++ data-structures quadtree


【解决方案1】:

想到的一些想法:

  1. 对于每个移动的点,检查它是否移出边界矩形 (bounds_)。如果是,请将其从树中移除。移动所有点后,要么将它们插入同一棵树,要么插入另一棵树。每隔一段时间(例如,当另一棵树的大小变为主树的 1/10 时),重建所有内容。
  2. 分割节点时,您可能会为每个子音符中的点计算一个边界矩形。执行此操作时,请在边界内留出一些余量,这样就可以将每个点移动几次迭代而不会超出边界。

这些想法对复杂性没有帮助(它仍然是 O(n*log(n)),但可能会提高速度。

【讨论】:

  • 我在代码中实现的第一个想法。但是它比重建整个树要慢,因为几乎每个节点都离开了他的矩形:(
猜你喜欢
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-12
相关资源
最近更新 更多