读取Matrix txt文件并存储为数组

时间:2009-02-21 13:12:53

标签: c++ matrix ifstream

我目前正在编写模拟退火代码来解决旅行商问题,并且在存储和使用来自txt文件的读取数据时遇到了困难。每一排&文件中的列代表每个城市,两个不同城市之间的距离存储为15 x 15矩阵:

0.0 5.0 5.0 6.0 7.0 2.0 5.0 2.0 1.0 5.0 5.0 1.0 2.0 7.1 5.0
5.0 0.0 5.0 5.0 5.0 2.0 5.0 1.0 5.0 6.0 6.0 6.0 6.0 1.0 7.1
5.0 5.0 0.0 6.0 1.0 6.0 5.0 5.0 1.0 6.0 5.0 7.0 1.0 5.0 6.0
6.0 5.0 6.0 0.0 5.0 2.0 1.0 6.0 5.0 6.0 2.0 1.0 2.0 1.0 5.0
7.0 5.0 1.0 5.0 0.0 7.0 1.0 1.0 2.0 1.0 5.0 6.0 2.0 2.0 5.0
2.0 2.0 6.0 2.0 7.0 0.0 5.0 5.0 6.0 5.0 2.0 5.0 1.0 2.0 5.0
5.0 5.0 5.0 1.0 1.0 5.0 0.0 2.0 6.0 1.0 5.0 7.0 5.0 1.0 6.0
2.0 1.0 5.0 6.0 1.0 5.0 2.0 0.0 7.0 6.0 2.0 1.0 1.0 5.0 2.0
1.0 5.0 1.0 5.0 2.0 6.0 6.0 7.0 0.0 5.0 5.0 5.0 1.0 6.0 6.0
5.0 6.0 6.0 6.0 1.0 5.0 1.0 6.0 5.0 0.0 7.0 1.0 2.0 5.0 2.0
5.0 6.0 5.0 2.0 5.0 2.0 5.0 2.0 5.0 7.0 0.0 2.0 1.0 2.0 1.0
1.0 6.0 7.0 1.0 6.0 5.0 7.0 1.0 5.0 1.0 2.0 0.0 5.0 6.0 5.0
2.0 6.0 1.0 2.0 2.0 1.0 5.0 1.0 1.0 2.0 1.0 5.0 0.0 7.0 6.0
7.0 1.0 5.0 1.0 2.0 2.0 1.0 5.0 6.0 5.0 2.0 6.0 7.0 0.0 5.0
5.0 7.0 6.0 5.0 5.0 5.0 6.0 2.0 6.0 2.0 1.0 5.0 6.0 5.0 0.0

要阅读本文,我有一个LoadCities()函数,如下所示:

#include "iostream"
#include "fstream"      
#include "string"   
using namespace std;

double distances [15][15];  

void LoadCities()
{
    ifstream CityFile;

    if (!CityFile.is_open()) //check is file has been opened
    {
        CityFile.open ("Cities.txt", ios::in | ios::out);

        if (!CityFile)
        {
            cerr << "Failed to open " << CityFile << endl;
            exit(EXIT_FAILURE);  //abort program
        }
    }

    int length;
    char * buffer;
    string cities;

    CityFile.seekg(0, ios::end);
    length = CityFile.tellg();
    CityFile.seekg (0, ios::beg);

    buffer = new char [length];

    cities = CityFile.read (buffer,length); 

    string rows = strtok(cities, "\n");

    distances = new double[rows.length()][rows.length()];

            for (int i = 0; i < (string) rows.length(); i++)
            {
                string distance = strtok(rows[i], " ");

                for (int j = 0; j < distance.length(); j++)
                {
                    distances[i][j] = (double) Parse(distance[j]);
                }
            }

    CityFile.close();
}

我尝试了一种替代的istreambuf_iterator方法,以便将读取材料操作到数组中,但是我似乎总是遇到并发症:

ifstream CityFile("Cities.txt");
string theString((std::istreambuf_iterator<char>(CityFile)), std::istreambuf_iterator<char>());

任何帮助都会受到很多关注。一直在抨击我,但收效甚微!

################编辑/更新

@ SoapBox - SA代码,函数和main()的一些细节。这不是干净,高效,整洁,并不是现阶段的工作,只需要暂时工作。此版本(下面)工作并设置为解决多项式(最简单的问题)。将其转换为旅行商问题需要做的是:

  1. 编写LoadCities()函数以收集距离数据。 (当前)

  2. 更改Initialise()以获取所涉及的距离总数

  3. 将E()更改为TSP功能(例如,计算随机路线的距离)

  4. 后两个我知道我可以做,但是我需要LoadCities()来做。在以下脚本中无需更改任何其他内容。

    #include "math.h"
    #include "iostream"
    #include "fstream"
    #include "time.h"   // Define time()
    #include "stdio.h"  // Define printf()
    #include "randomc.h"    // Define classes for random number generators
    #include "mersenne.cpp" // Include code for the chosen random number generator
    
    using namespace std; // For the use of text generation in application
    
    double T;
    double T_initial;
    
    double S;
    double S_initial;
    double S_current;
    double S_trial;
    
    double E_current;
    
    int N_step;        // Number of Iterations for State Search per Temperature
    int N_max;         //Number of Iterations for Temperature
    int Write;
    
    const double EXP = 2.718281828;
    
    //------------------------------------------------------------------------------
    //Problem Function of Primary Variable (Debugged 17/02/09 - Works as intended)
    
    double E(double x) //ORIGNINAL
    {
        double y = x*x - 6*x + 2;
    
         return y;
    }
    
    //------------------------------------------------------------------------------
    //Random Number Generation Function (Mod 19/02/09 - Generated integers only & fixed sequence)
    
    double Random_Number_Generator(double nHigh, double nLow) 
    {
        int seed = (int)time(0);            // Random seed
    
        CRandomMersenne RanGen(seed);       // Make instance of random number generator
    
        double fr;                          // Random floating point number
    
        fr = ((RanGen.Random() * (nHigh - nLow)) + nLow);   // Generatres Random Interger between nLow & nHigh
    
        return fr;
    }
    
    //------------------------------------------------------------------------------
    //Initializing Function (Temp 17/02/09)
    
    void Initialize() //E.g. Getting total Distance between Cities
    {
        S_initial = Random_Number_Generator(10, -10);
    
        cout << "S_Initial: " << S_initial << endl;
    }
    
    //------------------------------------------------------------------------------
    //Cooling Schedule Function (make variables) (Completed 16/02/09)
    
    double Schedule(double Temp, int i) // Need to find cooling schedule
    {
        double CoolingRate = 0.9999;
    
        return Temp *= CoolingRate; 
    }
    
    //------------------------------------------------------------------------------
    //Next State Function (Mod 18/02/09)
    
    double Next_State(double T_current, int i)
    {
            S_trial = Random_Number_Generator(pow(3, 0.5), pow(3, 0.5)*-1); 
    
            S_trial += S_current;
    
            double E_t = E(S_trial);
            double E_c = E(S_current);
    
            double deltaE = E_t - E_c;                              //Defines gradient of movement
    
            if ( deltaE <= 0 )                                      //Downhill
            {    
                S_current = S_trial;
                E_current = E_t;
            }
            else                                                    //Uphill
            {
                double R = Random_Number_Generator(1,0);            //pseudo random number generated
                double Ratio = 1-(float)i/(float)N_max;             //Control Parameter Convergence to 0
                double ctrl_pram = pow(EXP, (-deltaE / T_current)); //Control Parameter
    
                if (R < ctrl_pram*Ratio)                            //Checking 
                {   
                    S_current = S_trial;                            //Expresses probability of uphill acceptance
                    E_current = E_t;                                
                }
                else 
                    E_current = E_c;
            }
    
            return S_current;
    }
    
    //------------------------------------------------------------------------------
    //Metropolis Function (Mod 18/02/09)
    
    double Metropolis(double S_start, double T_current, int N_Steps, int N_temperatures)
    {
         S_current = S_start;                                       //Initialised S_initial equated to S_current
    
         for ( int i=1; i <= N_step; i++ )                          //Iteration of neighbour states
            S_current = Next_State(T_current, N_temperatures);      //Determines acceptance of new states
    
         return S_current;
    }
    
    //------------------------------------------------------------------------------
    //Write Results to Notepad (Completed 18/02/09)
    
    void WriteResults(double i, double T, double x, double y)
    {
    //This function opens a results file (if not already opened)
    //and stores results for one time step
    
        static ofstream OutputFile;
        const int MAXLENGTH = 80;
    
        if (!OutputFile.is_open()) //check is file has been opened
        {
            //no it hasn't. Get a file name and open it.
            char FileName[MAXLENGTH];
    
            //read file name
            cout << "Enter file name: ";
            do
            {
                cin.getline(FileName, MAXLENGTH);
            }
            while (strlen(FileName) <= 0); //try again if length of string is 0
    
            //open file
            OutputFile.open(FileName);
    
            // check if file was opened successfully
            if (!OutputFile)
            {
                cerr << "Failed to open " << FileName << endl;
                exit(EXIT_FAILURE);  //abort program
            }
    
            OutputFile << "Iterations" << '\t' << "Temperatures" << '\t' << "X-Value" << '\t' << "Y-Value" << endl; 
            OutputFile << endl;
        }
    
        //OutputFile.width(10);
        OutputFile << i << '\t' << T << '\t' << x << '\t' << y << endl; 
    
        if (i == N_max) 
        {   
            OutputFile << endl
                   << "Settings: " << endl
                   << "Initial Temperature: " << T_initial << endl
                   << "Temperature Iterations: " << N_max << endl
                   << "Step Iterations: " << N_step << endl
                   << endl
                   << "Results: " << endl
                   << "Final Temperature: " << T << endl 
                   << "Minimum: " << S << endl;
    
            OutputFile.close();
        }
    }
    
    //------------------------------------------------------------------------------
    //Main SA Function (Mod 17/02/09)
    
    void SA(int W)
    {
        S = S_initial;
        T = T_initial;
    
        for ( int N_temperatures = 1 ; N_temperatures <= N_max ; N_temperatures++ )
        {
            S = Metropolis( S, T, N_step, N_temperatures);
            T = Schedule(T, N_temperatures);
    
            if (W == 1)
                WriteResults(N_temperatures, T, S, E_current);
        }
    
        cout << "Result" << endl
        << "Y-value> " << S << endl
        << "Temperature> " << T << endl;
    
    }
    
    //------------------------------------------------------------------------------
    //Execution of Traveling Salesman Problem (Progress 18/02/09)
    
    
    int main()
    {
        cout << "Quadratic Function" << endl
             << "Solving method: Simulated Annealing" << endl;
        cout << "" << endl;
    
        cout << "Select desired Initial Temperature:" << endl
             << "> ";
        cin >> T_initial;
    
        cout << "Select desired number of Temperature Iterations:" << endl
             << "> ";
        cin >> N_max;
    
        cout << "Select desired number of step Iterations:" << endl
             << "> ";
        cin >> N_step;
    
        Initialize();
    
        cout << "Write to file: (1 / 0) " << endl
             << "> ";
        cin >> Write;
    
        SA(Write);
    
        system ("PAUSE");
    
        return 0;
    }
    
    @ strager - 我知道它的代码不好,但不幸的是,我的项目所涉及的时间限制和组合学习曲线,结果都是需要的! :)它将在后期阶段进行整理。

    @dirkgently - 这是这样做的最初原因,因此我的第一次尝试就是这样做。

5 个答案:

答案 0 :(得分:13)

这个怎么样? (KISS解决方案)

void LoadCities() {
  int x, y;
  ifstream in("Cities.txt");

  if (!in) {
    cout << "Cannot open file.\n";
    return;
  }

  for (y = 0; y < 15; y++) {
    for (x = 0; x < 15; x++) {
      in >> distances[x][y];
    }
  }

  in.close();
}

适合我。可能不是那么复杂,也许不是很高效,但只要你不读1000x1000数组,就不会有任何差别。

答案 1 :(得分:1)

它甚至可以编译吗?我得到了~7个错误。样本:

  

strtok(cities, "\n");

strtok()的第一个参数是char *而不是std :: string。

这有帮助吗?

void LoadCities()
{
  std::vector<double> f((std::istream_iterator<double>
       (std::ifstream("city.txt"))), /* replace filename with your own */
    (std::istream_iterator<double>()));
  if (!f.empty()) {
    std::cout << f.size() << "\n";
    /* print an arbitrary data point with 2 places of decimal */
    std::cout << std::setprecision(2) << f[ 0 ] << std::endl; 

  }
}

使用矩阵并不意味着您需要拥有多维数组。特别是,使用2D阵列。当然,它更容易阅读和写作;)

答案 2 :(得分:1)

你可能想要更简单的东西,比如:

std::vector<std::vector<std::string> > LoadCities(const std::string &filename)
{
    using namespace std;

    ifstream file;
    file.open(filename, ios::in | ios::out);

    if(!file.is_open()) {
        // error
        return vector<vector<double> >();
    }

    vector<vector<double> > data;
    string line;

    while(!std::getline(file, line, '\n').eof()) {
        istringstream reader(line);

        vector<double> lineData;

        string::const_iterator i = line.begin();

        while(!reader.eof()) {
            double val;
            reader << val;

            if(reader.fail())
                break;

            lineData.push_back(val);
        }

        data.push_back(lineData);
    }

    return data;
}

基本上您使用流来输入数据。我可能做错了(我从未处理过iostreams; P)但这应该会让你对如何构造矩阵读取器有一个大概的了解。

答案 3 :(得分:0)

以下是我加载/保存它的方法:

#include <iostream>
#include <fstream>
#include <string>

int width = 0;
int height = 0;
double **distances;

void WriteDouble( std::ofstream &stream, double toWrite )
{
    char buffer[8];
    memcpy( buffer, &toWrite, 8 );
    stream.write( buffer, 8 );
}

void WriteInt( std::ofstream &stream, int toWrite )
{
    char buffer[4];
    memcpy( buffer, &toWrite, 4 );
    stream.write( buffer, 4 );
}

double ReadDouble( std::ifstream &stream )
{
    double d = 0;
    stream.read( (char *)&d, 8 );
    return d;
}

int ReadInt( std::ifstream &stream )
{
    int i = 0;
    stream.read( (char *)&i, 4 );
    return i;
}

void Save()
{
    std::ofstream stream( "cities", std::ios::out | std::ios::binary );

    if( !stream.good() ) {
        throw std::exception( "Error opening stream" );
    }

    WriteInt( stream, width );
    WriteInt( stream, height );

    for( int x = 0; x < width; x++ ) {
        for( int y = 0; y < height; y++ ) {
            WriteDouble( stream, distances[x][y] );
        }
    }

    stream.close();
}

void Load()
{
    std::ifstream stream( "cities", std::ios::in | std::ios::binary );

    if( !stream.good() ) {
        throw std::exception( "Error opening stream" );
    }

    width = ReadInt( stream );
    height = ReadInt( stream );

    distances = new double *[width];

    for( int i = 0; i < width; i++ ) {
        distances[i] = new double[height];
    }

    for( int x = 0; x < width; x++ ) {
        for( int y = 0; y < height; y++ ) {
            distances[x][y] = ReadDouble( stream );
        }
    }

    stream.close();
}

void RunSaveTest()
{
    width = 15;
    height = 15;

    distances = new double *[width];

    for( int i = 0; i < width; i++ ) {
        distances[i] = new double[height];
    }

    for( int x = 0; x < width; x++ ) {
        for( int y = 0; y < height; y++ ) {
            distances[x][y] = (double)x / (double)( y + 1 );
            std::cout << distances[x][y] << std::endl;
        }
    }

    Save();
}

void RunLoadTest()
{
    Load();

    for( int x = 0; x < width; x++ ) {
        for( int y = 0; y < height; y++ ) {
            std::cout << distances[x][y] << std::endl;
        }
    }
}

int main()
{
    RunSaveTest();
    // RunLoadTest();

    return 0;
}

答案 4 :(得分:0)

我的博客参考:http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

此代码段具有更高的容错能力,而不是假设所有内容都格式正确。

#include <istream>
#include <string>
#include <sstream>
#include <vector>

// load matrix from an ascii text file.
void load_matrix(std::istream* is,
        std::vector< std::vector<double> >* matrix,
        const std::string& delim = " \t")
{
    using namespace std;

    string      line;
    string      strnum;

    // clear first
    matrix->clear();

    // parse line by line
    while (getline(*is, line))
    {
        matrix->push_back(vector<double>());

        for (string::const_iterator i = line.begin(); i != line.end(); ++ i)
        {
            // If i is not a delim, then append it to strnum
            if (delim.find(*i) == string::npos)
            {
                strnum += *i;
                if (i + 1 != line.end()) // If it's the last char, do not continue
                    continue;
            }

            // if strnum is still empty, it means the previous char is also a
            // delim (several delims appear together). Ignore this char.
            if (strnum.empty())
                continue;

            // If we reach here, we got a number. Convert it to double.
            double       number;

            istringstream(strnum) >> number;
            matrix->back().push_back(number);

            strnum.clear();
        }
    }
}

// example
#include <fstream>
#include <iostream>

int main()
{
    using namespace std;

    // read the file
    std::ifstream is("input.txt");

    // load the matrix
    std::vector< std::vector<double> > matrix;
    load_matrix(&is, &matrix);

    // print out the matrix
    cout << "The matrix is:" << endl;
    for (std::vector< std::vector<double> >::const_iterator it = matrix.begin(); it != matrix.end(); ++ it)
    {
        for (std::vector<double>::const_iterator itit = it->begin(); itit != it->end(); ++ itit)
            cout << *itit << '\t';

        cout << endl;
    }

    return 0;
}