C# · 12月 20, 2021

C++文件的读写和对多行多个字符串的处理

C++读写文件中的字符串

今天帮人做了个简单的作业,没想到花时间最多的不是算法而是文件的读写,还有对读入字符串的分割处理。晚上写作业的时候又用到了对字符串的处理,这里记录一下。

小白第一次写博客,做的不好的请多多指正。

题目如下:

Retail.dat文件中包含了某零售商店M的8万多条真实(16,470种)商品的销售记录(每行对应一条销售记录),现M店装修,需要把这些商品摆放在一个单行长柜中,如下:

… k K+1 K+2 …

其中每个格子仅放一种商品,且商店左右两侧各有一个门,顾客从左门进入挑选商品,并在把所有商品都加入购物篮后可以马上结帐从右门离去。注意顾客每次可能需要买多种商品,我们把顾客从进门选货到选完所有货物所经过的格子总数作为他的“购物不便程度”(以下简称“不便度”)度量,如:设顾客从左侧(格子编号从1开始)进入商店,他所需的货物分别摆放在101, 103, 210三个格子上,则该顾客的不便度为210。

请根据商品的历史销售记录,为装修后的M店设计一个合适的商品布局顺序,使得Retail.dat中所有顾客的总的不便度尽可能的小,并请编码实现和验证你的模型。程序的输入/输出要求描述如下:

输入:Retail.dat 文件

输出:Layout.dat 文件。该文件总共有16,470行,第2行至最后一行每行包含如下内容:

商品编号, 格子编号

如 “123,1”表示第123号商品应该摆放在第一个格子里面。

Layout.dat 文件的第一行是Retail.dat中所有购买记录在你的模型下的不便度的总和。

读入:从硬盘读入内存*ifstream *

首先将文件流对象与文件建立连接

注意这里判别是否打开失败很重要

我第一次做的时候文件根本没有读取到,但是我完全不知道。

把作业给朋友朋友也没有把文件放到同一位置,做一个简单的检验是有必要的。

string fileName = “retail.dat”;

in.open(fileName.data(),ios::in); //将文件流对象与文件连接起来

assert(in.is_open()); //如果打开失败,这里会终止运行

要求读入文件中的全部数字,文件中数字的存储方式为:

因为文件的输入输出都是以字符串的形式,我面对的问题是:如何读取文件中的每一个字符串并将他们转换成数字。

这里可以提一下我踩过的坑(首先我没有试过二进制读取和定义指针的读取):

1. 行末和行初会无法读入

string filename;

string line;

while (getline (in,line)) // line中不包括每行的换行符

{

cout << line << endl;

}

}

2. 直接用EOF判定文件末尾的,问题都是最后一行无法读入或无法停止循环

ifstream FILE(“test.txt”);

while (FILE.peek() != EOF)//修改

{

FILE.get(c);

cout << c;

}

3.试图直接逐个读取,但实际上行末或者行初会无法读入

string buffer;

fstream in;

in.open(“com.txt”,ios::in);

while(!in.eof())

{

in.getline(buffer,256,’n’);// 表示该行字符达到256个或遇到换行就结束

}

4.还有各种一边读入一边转换的骚操作,下次要一边尝试一边记录错误的经历

总而言之,最简单的做法应该是,逐行读取,在再提取空格,将单个字符串转换为数字。

注意这里用到了stringstream来再次读取从getline中读到的每一行,自动跳过空格。

stringstream ss(buffer);

这部分实现的代码如下:

string fileName = “retail.dat”;

ifstream in;

in.open(fileName.data(),ios::in); //将文件流对象与文件连接起来

assert(in.is_open());//如果打开失败,这里会终止运行

string buffer;

while (getline(in,buffer))//一次读取文件的一行内容,含空格,为buffer的字符串

{

int temp;

stringstream ss(buffer); //建立stringstream对象,初始化流内容为buffer所代表的字符串

while (ss >> temp) //从buffer中一次次读取数字存入temp,直到到达字符串流的末尾

{

…对ss进行操作

}

}

in.close();

写出:从内存写出到硬盘的文件夹

写出比读入简单,将要输出的文件和输出文件流(如果输出对象是屏幕这个流则为cout)联系起来以后,用法和cout一样,只是输出的对象不再是屏幕而是文件夹。

//默认打开方式是:如果原来存在,则删除原来的文件;没有这个文件会自动创建。

ofstream fout(“Layout.dat”);

for (int i = Size; i > 1; i–)

{

fout << bin[i].num << "," << Size-i+1 << endl;

}

fout.close();

我流快速排序

单纯记录一下(有错误的请dalao指正),注意swap是我重写的函数

void qsort(goods *a,int l,int r)

{

if (abs(r – l) == 1)

{

if (a[l] > a[r])

swap(a[l],a[r]);

return;

}

int pivot = l;

int p = l,q = r;

L++;

while(l<r)

{

while (a[r] > a[pivot]&& l < r)

r–;

while (a[l] <= a[pivot] && l < r)

L++;

swap(a[r],a[l]);

}

swap(a[pivot],a[l]);

if (p != l – 1)

qsort(a,p,l – 1);

else

return;

if (l + 1 != q)

qsort(a,l + 1,q);

else

return;

}

最后贴一下完整的实现代码:

#include

#include

#include

#include

#include

#include

#include

using namespace std;

const int Size = 16470;

struct goods

{

int num;

int value;

int degree;

//重载自定义结构的运算符,根据数据总的出现频率来判断大小,出现次数相同,作为顾客不便度的次数越大,看做出现频率越高

bool operator>(const goods &a)

{

if (this->value > a.value)

return 1;

else if (this->value == a.value&&this->degree > a.degree)

return 1;

else

return 0;

}

bool operator<=(const goods &a)

{

if (this->value

return 1;

else if (this->value == a.value&&this->degree <= a.degree)

return 1;

else return 0;

}

};

void swap(goods &l,goods &r)

{

goods t;

t = l;

l = r;

r = t;

}

void qsort(goods *a,q);

else

return;

}

long long int cum(goods *bin)

{

long long int count=0;

int temp[Size];

//temp[i]=k 即 序号为i的商品放在第k个货架上

for (int i = Size; i >= 1; i–)

{

temp[bin[i].num] =Size – i + 1 ;

}

for (int i = 1; i <= Size; i++)

{

if (bin[i].degree)

count += bin[i].degree*temp[bin[i].num];

}

return count;

}

int main()

{

string fileName = “retail.dat”;

goods bin[Size+1];//一个箱子,每个num代表着该类商品标号,value为个数

memset(bin,sizeof(bin));

ifstream in;

in.open(fileName.data(),为buffer的字符串

{

int temp;

int max = 0;//储存每一位顾客的不便度

stringstream ss(buffer); //建立stringstream对象,初始化流内容为buffer所代表的字符串

while (ss >> temp) //从buffer中一次次读取数字存入temp,直到到达字符串流的末尾

{

if (temp > max)

max = temp;//记下这个顾客的不方便度的序号

bin[temp].num = temp; //读到一个名为num的商品,暂时的编号为temp,等待排序

bin[temp].value++; //所以名为num的商品暂时被使用了value次

}

bin[max].degree++;

}

in.close();

qsort(bin,1,Size);//快速排序,按照被拿的次数排序

long long int inconvient = cum(bin);

ofstream fout(“Layout.dat”);

fout << "这个模型的复杂度是: "<<inconvient << endl;

for (int i = Size; i > 1; i–)

{

fout << bin[i].num << "," << Size-i+1 << endl;

}

fout.close();

system(“pause”);

return 0;

}