Lesen einer Matrix TXT-Datei und zum Speichern als ein Array
Frage
Ich schreibe derzeit ein simuliertes Ausglühen Code ein Reiseproblem zu lösen, und haben in Schwierigkeiten mit der Speicherung und meine gelesenen Daten aus einer txt-Datei. Jede Zeile & Spalte in der Datei repräsentiert jede Stadt, wobei der Abstand zwischen zwei verschiedenen Städten als gespeichert 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
Um dies zu lesen Ich habe eine LoadCities () Funktion wie folgt:
#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();
}
Ich habe eine alternative istreambuf_iterator Methode versucht, den Punkt zu bringen das Lesematerial in Arrays zu manipulieren, aber immer in Komplikationen zu laufen scheine ich:
ifstream CityFile("Cities.txt");
string theString((std::istreambuf_iterator<char>(CityFile)), std::istreambuf_iterator<char>());
Jede Hilfe würde viel appriciated. Wurde meinen Kopf gegen diesen mit wenig Erfolg Bashing!
################ EDIT / Update@ SoapBox - einige Details des SA-Code, Funktionen und main (). Das ist nicht sauber, effizient, sauber und ist nicht ment in diesem Stadium zu sein, muss nur für den Augenblick arbeiten. Diese Version (unten) arbeitet und Setup-Polynome zu lösen (einfachste Probleme). Was muss getan werden, es Problem zu einem Handlungsreisenden konvertieren ist:
-
Schreiben Sie die LoadCities () Funktion der Abstandsdaten zu sammeln. (Current)
-
Ändern Initialise (), um die Summe der Entfernungen zu bekommen beteiligt
-
Ändern E () auf die TSP-Funktion (z.B. Berechnen einer Entfernung Random-Route)
Die beiden letzteren ich weiß, was ich tun kann, aber ich benötige LoadCities (), es zu tun. Nichts anderes muss im folgenden Skript geändert werden.
#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 - Ich weiß, seinen schlechten Code, aber leider mit den Zeitzwängen für mein Projekt und die consiquental Lernkurve, die Ergebnisse sind, was notwendig ist! :) Es wird in späteren Phasen in Ordnung gebracht werden.
@ dirkgently -. Das war der ursprüngliche Grund für es auf diese Weise zu tun und damit, warum mein erster Versuch, es zu gehen, ist wie so
Lösung
Wie wäre es damit? ( KISS Lösung)
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();
}
Funktioniert für mich. Vielleicht nicht so komplex sein und vielleicht nicht sehr performant, aber solange man nicht eine 1000x1000 Array lesen, werden Sie keinen Unterschied sehen.
Andere Tipps
Sie wollen wahrscheinlich etwas einfacher, wie folgt aus:
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;
}
Im Grunde verwenden Sie Ströme zur Eingabe der Daten. Ich bin wahrscheinlich etwas falsch zu machen (ich habe noch nie mit iostreams behandelt; P). Aber diese sollten Sie die allgemeine Vorstellung davon, wie eine Matrix Leser zu strukturieren
Ist es sogar kompilieren? Ich erhalte ~ 7 Fehler. Ein Beispiel:
strtok(cities, "\n");
strtok()
erstes Argument ist ein char *
und kein std :: string.
Ist diese Hilfe?
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;
}
}
mit Matrizen Arbeiten bedeutet nicht, dass Sie ein mehrdimensionales Array haben müssen. Insbesondere mit 2D-Arrays. Natürlich ist es leichter zu lesen und schreiben;)
Hier ist, wie ich laden / speichern:
#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;
}
Referenz aus meinem Blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/
Dieser Code-Schnipsel hat eine höhere Fehlertoleranz statt vorausgesetzt, alles ist gut formatiert.
#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;
}