在矩形qt中生成随机坐标

时间:2016-06-14 12:12:25

标签: c++ qt random

我有一个长度为27.5且宽度为3.5的矩形,我应该在这个矩形内生成唯一的坐标,即没有任何重复。需要生成的坐标数基于列表的大小。以下是我到目前为止使用Qt做的事情:

struct coordinates_t{
    int x;
    int y;    
};

QVector<coordinates_t> coordinatesList;
QList<QString> listOfDevices;
//populate listOfDevices

for( int i = 0; i < listOfDevices.count(); i++)
{
coordinatesList.pushback({rand() % 51 + (-25), rand() % 11 + (-5)});
}

现在的问题是,即使rand函数在矩形内生成随机数,但它也不会避免重复。在某种程度上我可以避免重复并在给定的矩形内产生唯一的坐标。

3 个答案:

答案 0 :(得分:3)

解决这个问题的正常方法是改组一组预定义的坐标。但在这种情况下,这不实用。此外,也允许在一个轴上重复。

考虑通过

解决这个问题
  1. 定义bool operator<(const coordinates_t& other) constbool operator==(const coordinates_t& other) const

  2. 使用std::set<coordinates_t>。一旦你完成了(1),这是可能的。

  3. 将随机坐标插入set ,直到达到所需的集合大小。

  4. 如果您仍然需要以这种方式存储,请将该集合复制到QVector。如果要保留插入顺序(set将根据您在(1)中定义运算符的方式对值进行排序),则保留QVector,并且只有在插入时才向其推送一个点set成功了。

  5. 将副本插入set是O(Log N)no-op。另请注意,rand()作为线性同余生成器可能会抛出不期望的自相关效应,这些效应尤其在x,y图中表现出来。考虑使用Mersenne Twister代替。

答案 1 :(得分:2)

以下是演示使用QVectorQPoint检查重复项的示例。如果您想将QVector::contains与您自己的结构一起使用,则必须实现operator==()

#include <QCoreApplication>
#include <QVector>
#include <QPoint>
#include <QDateTime>    
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVector<QPoint> point_vector;
    qsrand(QDateTime::currentMSecsSinceEpoch());

    const int max_points = 20;

    while(point_vector.size() < max_points)
    {
        QPoint point(qrand() % 27, qrand() % 4);
        if(!point_vector.contains(point))
            point_vector.append(point);
    }

    qDebug() << point_vector;
    return a.exec();
}

答案 2 :(得分:0)

为了完整起见。 :)

在我的评论中,我建议使用 QMap ,但我考虑到了 std :: set ,这在Qt中没有等价物。 :(

无论如何,我想看看 QMap 是否也可以做到这一点并想出一个......有点奇怪的方法。

QPoint 放入 QMap 不起作用,因为插入的需要实施<运算符,不是 QPoint 的情况,而是 QPair 的情况。因此我的选择。

想法是(有点像 thuga 的答案)将结果列表的size()与设备列表进行比较并插入,直到它们等长。但是,由于我自己使用 QMap ,这是我的版本。 :)

#include <ctime>
#include <QMap>
#include <QDebug>
#include <QPair>

int main()
{
    qsrand(std::time(nullptr));

    QMap<QPair<int, int>, QString> coords;

    QList<QString> listOfDevices;
    //populate listOfDevices
    for (int i = 10; i < 30; ++i) {
        listOfDevices.append("dev" + QString::number(i));
    }

    qDebug() << "Number of devices:" << listOfDevices.size();

    int demo_counter = 0;
    while (coords.size() < listOfDevices.size()) {
        coords.insert(
                qMakePair(qrand() % 51 + (-25), qrand() % 11 + (-5)),
                listOfDevices.at(coords.size())
                );
        ++demo_counter;
    }

    for (auto it = coords.cbegin(); it != coords.cend(); ++it) {
        qDebug() << it.key() << ':' << it.value();
    }
    qDebug() << "Entries inserted:" << coords.size();
    qDebug() << "Tries needed:" << demo_counter;

    return 0;
}

此输出(请参阅 23 次添加 20 条目的次数):

Number of devices: 20
QPair(-25,-2) : "dev14"
QPair(-23,3) : "dev28"
QPair(-22,5) : "dev20"
QPair(-20,5) : "dev11"
QPair(-19,-1) : "dev22"
QPair(-19,0) : "dev27"
QPair(0,-2) : "dev29"
QPair(5,-3) : "dev23"
QPair(9,0) : "dev28"
QPair(10,1) : "dev17"
QPair(11,-5) : "dev18"
QPair(11,4) : "dev25"
QPair(16,-2) : "dev12"
QPair(16,4) : "dev26"
QPair(21,-2) : "dev26"
QPair(21,2) : "dev16"
QPair(21,4) : "dev15"
QPair(23,-2) : "dev24"
QPair(25,2) : "dev21"
QPair(25,4) : "dev23"
Entries inserted: 20
Tries needed: 23

由于您的要求不是很清楚,并且您也可以在while循环中填写设备,因此无法确定哪种解决方案更适合但如果你真的想要两个不同的列表,一个是设备,另一个是 coords ,那么首选contains()检查的解决方案。