读取Matrix txt文件并存储为数组
我目前正在编写模拟退火代码来解决旅行推销员问题,但在存储和使用从 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>());
任何帮助将不胜感激。 我一直在努力反对这一点,但收效甚微!
################ EDIT / Update@ SoapBox - SA 代码、函数和 main() 的一些细节。 这不干净、高效、整洁,现阶段不适合,只需要暂时工作。 这个版本(如下)可以工作并且被设置为解决多项式(最简单的问题)。 将其转换为旅行商问题需要做的是:
编写 LoadCities() 函数来收集距离数据。 (当前)
更改Initialise()以获取所涉及的总距离
将E()更改为TSP函数(例如,计算随机路线)
后两个我知道我可以做到,但是我需要 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 - 这是这样做的最初原因,因此我的第一次尝试就是这样进行。
I'm currently writing a Simulated Annealing code to solve a traveling salesman problem and have run into difficulties with storing and using my read data from a txt file. Each row & column in the file represents each city, with the distance between two different cities stored as a 15 x 15 matrix:
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
To read this I have a LoadCities() function as shown below:
#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();
}
I've attempted an alternative istreambuf_iterator method to get to the point of manipulating the read material into arrays, however I always seem to run into complications:
ifstream CityFile("Cities.txt");
string theString((std::istreambuf_iterator<char>(CityFile)), std::istreambuf_iterator<char>());
Any help would be much appriciated. Been bashing my head against this with little success!
################ EDIT / Update
@ SoapBox - Some Detail of the SA code, functions and main(). This is not clean, efficient, tidy and isn't ment to be at this stage, just needs to work for the moment. This version (below) works and is setup to solve polynomials (simplest problems). What needs to be done to convert it to a Traveling Salesman Problem is to:
Write the LoadCities() function to gather the distance data. (Current)
Change Initialise() to get the Total of the distances involved
Change E() to the TSP function (e.g. Calculate distance of a random route)
The latter two I know I can do, however I require LoadCities() to do it. Nothing else needs to be changed in the following script.
#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 - I know its bad code, but unfortunatly with the time constraints involved for my project and the consiquental learning curve, results are what are needed! :) It'll be tidied up at latter stages.
@ dirkgently - That was the initial reason for doing it this way, and hence why my first attempt is to go at it like so.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这个怎么样? (KISS 解决方案)
对我有用。 可能没那么复杂,性能也可能不是很高,但只要您不读取 1000x1000 数组,您就不会看到任何差异。
How about this? (KISS solution)
Works for me. Might not be that complex and perhaps isn't very performant, but as long as you aren't reading a 1000x1000 array, you won't see any difference.
您可能想要更简单的东西,如下所示:
基本上您使用流来输入数据。 我可能做错了什么(我从未处理过 iostreams;P),但这应该让您了解如何构造矩阵读取器。
You probably want something simpler, like this:
Basically you use streams to input the data. I'm probably doing something wrong (I have never dealt with iostreams ;P) but this should give you the general idea of how to structure a matrix reader.
它甚至可以编译吗? 我收到约 7 个错误。 一个样品:
strtok()
的第一个参数是char *
而不是 std::string。这有帮助吗?
使用矩阵并不意味着您需要多维数组。 特别是对于二维数组。 当然,它更容易阅读和编写;)
Does it even compile? I get ~7 errors. A sample:
strtok()
's first argument is achar *
and not a std::string.Does this help?
Working with matrices doesn't mean you need to have a multidimensional array. Especially, with 2D arrays. Of course it's easier to read and write ;)
这是我加载/保存它的方法:
Here is how I would load/save it:
参考我的博客: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/
此代码片段具有更高的容错能力,而不是假设一切格式良好。
Reference from my blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/
This code snippet has higher fault tolerance instead of assuming everything is well formatted.