c++ - 如何在数据文件上找到最接近第一个点的点? C++

标签 c++

我的数据文件如下所示:

x              y               z
0.068472     -0.024941       0.028884
....         ....            ....
continued, there are more than 100 points. 


我想在所有数据点中找到最接近点1的点(在
这种情况(0.068472,-0.024941,0.028884)。我的读取文件的代码在下面,我应该添加哪个函数以找到与点1最接近的点?我应该使用最小函数来找到点1和另一个点之间的最小距离吗?但是我不确定如何用代码编写。

// Program to read an input file 

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    const int MAXI = 1000;
    double x, y, z, xcoordinates[MAXI], ycoordinates[MAXI], zcoordinates[MAXI];
    int i, count;

    ifstream inFile("input-week6-ad-q4-2.txt"); // ifstream function to read the file
    string line, c; // To read the characters

    if (inFile.is_open()) {
        getline(inFile, line); // To read the header of the input file then     discard it
        getline(inFile, line);

        i = 0;
        count = 0;
        while (inFile >> x >> y >> z) {
            xcoordinates[count] = x;
            ycoordinates[count] = y;
            zcoordinates[count] = z;
            count = count + 1;
        }

        for (i = 0; i < count; i++) {
            cout << xcoordinates[i] << " " << ycoordinates[i] << " " << zcoordinates[i] << "\n";
        }

        inFile.close();
    } else {
        cout << "The file could not be opened." << "\n"; // To check for any error
    }

    system("pause");
    return 0;
}

最佳答案

这些评论提供了正确的方向。如果要编写的最小距离查找器是C ++,则应从简单的2d点类开始,然后通过添加第3个坐标来派生一个类来处理该类中的3d点。如果您只是要使用单独的x, y, z坐标和三个单独的double数组-您最好使用C语言编写程序。

为2d点编写基类一点都不困难。为了从中派生3d类,您需要注意的唯一事情是将坐标成员声明为protected:,以便2d点类的所有受保护成员都可以作为3d类(类(类)中的受保护成员)使用。成员默认情况下是私有的,除非有朋友,否则永远无法访问基础的私有成员)

那么最小的二维点基类是什么样的呢?好吧,您将需要x, y坐标,并且需要一个默认的构造函数来将xy设置为0.0 when the class is constructed, a constructor to take x and y values, and then a couple of accessor functions to get the x and y`值,以用于距离函数。

最小的二维点类可以是:

/* 2D Cartesian Coordinate Point */
class point2_t {
  protected:        /* allows derived class access to x, y when inherited */
    double x, y;    /* private members would not be accessible */
  public:
    point2_t () { x = 0.0, y = 0.0; }   /* constructors */
    point2_t (const double a, const double b) : x{a}, y{b} { }
    const double& getx () const { return x; }   /* access functions */
    const double& gety () const { return y; }
    double dist (const point2_t& p) {           /* distance function */
        return sqrt ((x-p.getx()) * (x-p.getx()) +
                     (y-p.gety()) * (y-p.gety()));
    }
};


这将使您可以使用值初始化2d点,获取当前设置的值,然后计算与其他2d点的距离。尽管这很好用,但仍然需要从文件中读取xy值,然后通过将坐标传递给构造函数来创建点。 (您还可以编写一个setx(double x)和相应的sety()以允许您更改x, y值)

能够仅cin >> point;并自动设置x, y值,并能够cout << point;输出坐标,这将是非常不错的。您可以通过重载<<>>运算符来实现。这使得读取和输出坐标数据非常方便。为此,您可以将以下内容添加为成员函数:

    /* overload output and input operators */
    friend std::ostream& operator << (std::ostream& os, const point2_t& p) {
        os << "(" << p.x << ", " << p.y << ")";
        return os;
    }
    friend std::istream& operator >> (std::istream& is, point2_t& p) {
        is >> p.x >> p.y;
        return is;
    }


一旦编写了2d点类,您所要做的就是从中派生3d点类,并添加一个z坐标和相应的函数来处理所有三个坐标而不是两个坐标。从包括该基类的受保护成员的基类派生一个类的基本形式是:

class derived : public base {
    /* additions */
};


从2d点类到3d点类(包括重载的<<>>运算符)的简单派生可能是:

/* 3D Cartesian Coordinate Point derived from 2D point class */
class point_t: public point2_t {
  protected:
    double z;   /* add z coordinate */
  public:
    point_t () { point2_t (0.0, 0.0); z = 0.0; };   /* default construct */
    /* construct with initializer list */
    point_t (const double a, const double b, const double c) :
                point2_t (a, b), z{c} {}
    const double& getz () const { return z; }       /* add getz accessor */
    double dist (const point_t& p) {                /* extend distance */
        return sqrt ((x-p.getx()) * (x-p.getx()) +
                     (y-p.gety()) * (y-p.gety()) +
                     (z-p.getz()) * (z-p.getz()));
    }
    /* extend operators */
    friend std::ostream& operator << (std::ostream& os, const point_t& p) {
        os << "(" << p.x << ", " << p.y << ", " << p.z << ")";
        return os;
    }
    friend std::istream& operator >> (std::istream& is, point_t& p) {
        is >> p.x >> p.y >> p.z;
        return is;
    }
};


现在您有了一个3d点类,可以计算点之间的距离。剩下的工作就是为第一个点创建一个类的实例,并为您的文件创建另一个临时实例以从文件中读取其他点,从而使您可以计算两者之间的距离。 (如果要保存最近点的坐标,则第三个实例很方便)

数据文件的唯一警告是您需要丢弃包含x y z标题的第一行。虽然您可以使用string将行读入getline并忽略它,但C ++还提供了流函数.ignore(),它允许您忽略最多可读字符数,直到达到分隔符为止(换行)。只需包含limits标头,即可使用:

    std::ifstream f (argv[1]);  /* open file stream */
    ...
    /* discard 1st line in file */
    f.ignore(std::numeric_limits<std::streamsize>::max(), '\n');


(两种方法都可行)

无需将文件中的所有点都读取到容器中以供以后处理,而只需查找第一个点与其余点之间的最小距离即可。您需要做的就是存储第一个点(下面的p1),然后计算它与其余点之间的距离,并保存为每个后续比较找到的最小距离(下面的distmin)。 (如果愿意,还可以保存最近点的坐标)

将其组合成一个简短的main()可能看起来像:

int main (int argc, char **argv) {

    if (argc < 2) { /* validate argument available for filename */
        std::cerr << "error: insufficient input.\n";
        return 1;
    }

    std::ifstream f (argv[1]);  /* open file stream */
    point_t p1, min, tmp;       /* 1st, mininum & temporary points */
    /* initialize minimum distance to maximum allowable */
    double distmin = std::numeric_limits<double>::max();

    /* discard 1st line in file */
    f.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    if (!(f >> p1)) {   /* read 1st point */
        std::cerr << "error: failed read of p1\n";
        return 1;
    }
    while (f >> tmp) {  /* read remaining points */
        double dist = tmp.dist (p1);    /* get distance from p1 */
        if (dist < distmin) {           /* check less than distmin? */
            distmin = dist;             /* set new distmin */
            min = tmp;                  /* set new closest point */
        }
    }
    /* output results */
    std::cout << "\nclosest point to " << p1 << "\n\n" << min <<
                "\n\ndistance: " << distmin << '\n';
}


完整的示例如下:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <limits>

/* 2D Cartesian Coordinate Point */
class point2_t {
  protected:        /* allows derived class access to x, y when inherited */
    double x, y;    /* private members would not be accessible */
  public:
    point2_t () { x = 0.0, y = 0.0; }   /* constructors */
    point2_t (const double a, const double b) : x{a}, y{b} { }
    const double& getx () const { return x; }   /* access functions */
    const double& gety () const { return y; }
    double dist (const point2_t& p) {           /* distance function */
        return sqrt ((x-p.getx()) * (x-p.getx()) +
                     (y-p.gety()) * (y-p.gety()));
    }
    /* overload output and input operators */
    friend std::ostream& operator << (std::ostream& os, const point2_t& p) {
        os << "(" << p.x << ", " << p.y << ")";
        return os;
    }
    friend std::istream& operator >> (std::istream& is, point2_t& p) {
        is >> p.x >> p.y;
        return is;
    }
};

/* 3D Cartesian Coordinate Point derived from 2D point class */
class point_t: public point2_t {
  protected:
    double z;   /* add z coordinate */
  public:
    point_t () { point2_t (0.0, 0.0); z = 0.0; };   /* default construct */
    /* construct with initializer list */
    point_t (const double a, const double b, const double c) :
                point2_t (a, b), z{c} {}
    const double& getz () const { return z; }       /* add getz accessor */
    double dist (const point_t& p) {                /* extend distance */
        return sqrt ((x-p.getx()) * (x-p.getx()) +
                     (y-p.gety()) * (y-p.gety()) +
                     (z-p.getz()) * (z-p.getz()));
    }
    /* extend operators */
    friend std::ostream& operator << (std::ostream& os, const point_t& p) {
        os << "(" << p.x << ", " << p.y << ", " << p.z << ")";
        return os;
    }
    friend std::istream& operator >> (std::istream& is, point_t& p) {
        is >> p.x >> p.y >> p.z;
        return is;
    }
};

int main (int argc, char **argv) {

    if (argc < 2) { /* validate argument available for filename */
        std::cerr << "error: insufficient input.\n";
        return 1;
    }

    std::ifstream f (argv[1]);  /* open file stream */
    point_t p1, min, tmp;       /* 1st, mininum & temporary points */
    /* initialize minimum distance to maximum allowable */
    double distmin = std::numeric_limits<double>::max();

    /* discard 1st line in file */
    f.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    if (!(f >> p1)) {   /* read 1st point */
        std::cerr << "error: failed read of p1\n";
        return 1;
    }
    while (f >> tmp) {  /* read remaining points */
        double dist = tmp.dist (p1);    /* get distance from p1 */
        if (dist < distmin) {           /* check less than distmin? */
            distmin = dist;             /* set new distmin */
            min = tmp;                  /* set new closest point */
        }
    }
    /* output results */
    std::cout << "\nclosest point to " << p1 << "\n\n" << min <<
                "\n\ndistance: " << distmin << '\n';
}


输入文件示例

在与您的值相同的范围内生成一些其他随机点将为您提供一个总点数为10的数据文件,用于验证程序,例如

$ cat dat/3dpoints-10.txt
x              y               z
0.068472     -0.024941       0.028884
-0.023238      0.028574      -0.021372
 0.015325     -0.086100       0.011980
-0.028137     -0.025350       0.021614
-0.013860      0.015710      -0.022659
 0.026026     -0.093600       0.019175
 0.010445     -0.098790       0.023332
-0.021594      0.017428      -0.025986
 0.021800     -0.027678       0.017078
-0.016704      0.017951       0.011059


使用/输出示例

然后,运行程序将找到最接近您的第一个点(p1)的点,并提供以下答案:

$ ./bin/point_distmin dat/3dpoints-10.txt

closest point to (0.068472, -0.024941, 0.028884)

(0.0218, -0.027678, 0.017078)

distance: 0.0482198


仔细检查一下,如果您有任何问题,请告诉我。 cpprefernce.com是最好的参考文献之一(除了标准本身)。请将该书签放在手边,并花一些时间来了解该语言和网站。

关于c++ - 如何在数据文件上找到最接近第一个点的点? C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55192641/

相关文章:

c++ - 返回包含 std::map 的 std::unique_ptr

c++ - 比较 C++ 中的类类型

c++ - 为什么编译器在可能的情况下不使虚函数成为非虚函数?

c++ - 如何解决 Paddle v0.8.0b 上的 "cudaSuccess = err (0 vs. 8)"错误?

c++ - C++ 中的特征库给出错误 C2660 : 'Eigen::MatrixBase<Derived>::eigenvalues' : function does not take 2 arguments

c++ - 将 1Byte 数据转换为 4Byte 时详细发生了什么

c++ - 检查这是否为空

c++ - 哪一种是在 C++ 中分配未初始化内存的最惯用的方法

c++ - 算法不适用于非常量对象的 const_iterator

c++ - 一旦你采用了 boost 的智能指针,有没有使用原始指针的情况?