点遍历的最佳数据结构

时间:2017-08-18 11:34:36

标签: c++ data-structures

寻找C ++解决方案。

我想过是否在这里或MathExchange等问这个问题,但因为它更像是一个基于编程的问题,因此在这里发帖。

真正的问题:

我有一个XML字段为:

<part name='01' x='351' y='151'/>

在x和y的位置,我存储为QPointf个对象。另外,我需要将name=01值与QPointf对象一起映射以创建地图。

现在我需要在此地图上执行某些操作:

  • 首先,我需要获得所有点数(QPointf)并绘制图像。
  • 其次,我将修改从GUI获取点的某些点的x和y值。
  • 当我从GUI获取点数时,我需要检查每个Qpointf内部地图中的x和y值。

更简单的问题:

我正在寻找一种数据结构,使得它不是拥有keyQPointf的映射,而是更容易解析和查找点的x和y值(QPointf)。只是QPointf和key应该相互形成一个唯一的对,这样解析整个点列表就可以找到某个(x,y)并修改它更快,即使修改了QPointf的x和y值也是如此附在它上面是一样的。

PS:我希望我对问题很清楚,如果有什么不清楚的话请编辑/评论,以便改善问题。

2 个答案:

答案 0 :(得分:1)

因此,如果我理解正确,您只需要一种简单的方法来存储积分数据。

这在性能方面并不是最好的,但是如果你没有计划在每一帧都改变它,它就不会有任何问题:

#include <map>
typedef std::map<int, std::pair<float, float>> PointContainer;

QPointf* fromPointContainer(PointContainer points)
{
    QPointf array = new QPointf[points.size()];
    for (size_t i; i < points.size(); i++) 
        array[i] = QPointf(points[i].first, points[i].second);
    return array;
}

int main() {
    PointContainer points;
    points[0] = { 1.6f/*x*/, 5.8f/*y*/ };
    QPointf* array = fromPointContainer(points);
    //render here
    delete array;//don't forget to delete the array allocated with new
    return 0;
}

答案 1 :(得分:1)

我的猜测是,您最重要的方面是在用户使用UI时找到一组特定的x和y点。有许多加速结构可能,但我可能会推荐point index grid。也就是说,您将点的索引分区为2D桶。当用户在UI中选择一个点时,您可以快速查找该点所在的存储桶,然后您可以仅迭代该存储桶中的点以查找实际点。

至于你的数据,我会将它存储在一个数组中:

struct NamePoint {
    int name, x, y;
};
std::vector<NamePoint> points;

现在,您将创建一个引用points数组的点索引网格。自己实现一个可能是值得的,但除此之外我知道存在一个有效的OpenVDB版本。

我做了一个小的脏实现,所以你可以看到原理。我没有检查输入,所以如果你不小心你将访问向量的边界(例如,调用pointIndexGrid.indicesForPoint(5, 5)给出分段错误)。

#include <iostream>
#include <vector>
#include <limits>

struct NamePoint {
    int name, x, y;
};

template <typename T> // Just so any array type can work
struct PointIndexGrid {
    using ArrayType = T;
    using size_type = typename ArrayType::size_type;

    PointIndexGrid(const ArrayType& points, int gridSize)
        : mGridSize(gridSize) 
    {
        // Find the domain. We will create a 2D vector which will all contain another vector with indices.
        maxX = maxY = std::numeric_limits<int>::min();
        minX = minY = std::numeric_limits<int>::max();
        for (const auto& p : points) {
            maxX = p.x > maxX ? p.x : maxX;
            maxY = p.y > maxY ? p.y : maxY;
            minX = p.x < minX ? p.x : minX;
            minY = p.x < minY ? p.x : minY;
        }

        // create buckets
        int nbrXBuckets = (maxX - minX)/mGridSize + 1; // Due to integer arithmetics we round down -- lets add one extra just in case
        int nbrYBuckets = (maxY - minY)/mGridSize + 1;
        for (int n = 0; n < nbrXBuckets; ++n) {
            mBuckets.emplace_back(std::vector<std::vector<size_type>>(nbrYBuckets));
        }

        // Partition points
        for (size_type i = 0; i < points.size(); ++i) {
            int xBucket = (points[i].x - minX)/mGridSize; // this is the method how to easily calculate the bucket. Pure arithmetics -- goes fast
            int yBucket = (points[i].y - minY)/mGridSize;
            mBuckets[xBucket][yBucket].emplace_back(i);
        }
    }

    std::vector<size_type> indicesForPoint(int x, int y) 
    {
        int xBucket = (x - minX)/mGridSize; // Same as above
        int yBucket = (y - minY)/mGridSize;
        return mBuckets[xBucket][yBucket];
    }

private:
    int mGridSize;
    int maxX, minX;
    int maxY, minY;
    std::vector<std::vector<std::vector<size_type>>> mBuckets;
};

int main() {
    std::vector<NamePoint> points;
    points.emplace_back(NamePoint{1, 1, 1});
    points.emplace_back(NamePoint{2, 1, 2});
    points.emplace_back(NamePoint{3, 1, 2});
    points.emplace_back(NamePoint{4, 2, 2});
    points.emplace_back(NamePoint{5, 3, 3});

    PointIndexGrid<std::vector<NamePoint>> pointIndexGrid(points, 2);

    std::cout << "Indices for (1, 1): " << std::endl;
    for (const auto& i : pointIndexGrid.indicesForPoint(1, 1)) {
        std::cout << " " << i << std::endl;
    }

    std::cout << "Indices for (3, 3): " << std::endl;
    for (const auto& i : pointIndexGrid.indicesForPoint(3, 3)) {
        std::cout << " " << i << std::endl;
    }
}

打印出来:

Indices for (1, 1): 
 0
 1
 2
 3
Indices for (3, 3): 
 4

所以要在特定的(x, y)找到一个点:

  1. 使用PointIndexGrid分区所有点。
  2. 使用pointIndexGrid.indicesForPoint(x, y)
  3. 遍历那里的所有索引(并查找points - 数组中的点数。)
  4. 抓住你想要的点。