【问题标题】:Order files with MergeSort in c++在 C++ 中使用 MergeSort 对文件进行排序
【发布时间】:2014-04-07 07:41:11
【问题描述】:

我正在尝试实现我自己的 MergeSort,但我遇到了一些问题,看看是否有人可以帮助我一点。

我有一个大文件,其中包含一些以逗号分隔的信息(姓名、城市、邮件、telf)。我想应用归并排序来订购它,因为我假设客户端计算机一次尝试就没有那么多内存。

所以,我将它拆分为 MAX_CUSTOMERS 行的文件,并单独订购它们,直到这里都是正确的,但是当我想要获取前两个文件并订购它们时,我遇到了所有问题,我重复了,和其他人消失,这是我的代码:

void MergeSort(string file1Name, string file2Name,string name){
printf("Enter MERGE SORT %s AND %s\n",file1Name.c_str(),file2Name.c_str());
string temp;
string fileName;
string lineFile1, lineFile2;
bool endFil1 = false, endFil2 = false;
int numCust1 = 0;
int numCust2 = 0;
int x1 = 0, x2 = 0;

ifstream file1;
file1.open(file1Name.c_str());
ifstream file2;
file2.open(file2Name.c_str());

ofstream mergeFile; 
fileName = "customers_" +name +".txt";
cout << "Result file " << fileName << endl;
mergeFile.open("temp.txt");

getline(file1,lineFile1);
getline(file2,lineFile2);

while(!endFil1 && !endFil2){
    if(CompareTelf(lineFile1,lineFile2)==1){
        mergeFile << lineFile1 << endl;
        if(!getline(file1,lineFile1)){
            cout << lineFile1 << endl;
            cout << "1st file end" << endl;         
            endFil1 = true;
        }
    }else{
        mergeFile << lineFile2 << endl;
        if(!getline(file2,lineFile2)){
            cout << lineFile2 << endl;
            cout << "2nd file end" << endl;         
            endFil2 = true;
        }
    }       
}
if(endFil1){
    //mergeFile << lineFile2 << endl;
    while(getline(file2,lineFile2)){
        mergeFile << lineFile2 << endl;
    }
}else{
    //mergeFile << lineFile1 << endl;
    while(getline(file1,lineFile1)){
        mergeFile << lineFile1 << endl;
    }
}

file1.close();
file2.close();
mergeFile.close();
rename("temp.txt",fileName.c_str());
return;
}

Customer SplitLine(string line){
string splitLine;
string temp;
Customer cust;
int actProp = 0;
int number;
istringstream readLineStream(line); //convert String readLine to Stream readLine

while(getline(readLineStream,splitLine,',')){
    if (actProp == 0)cust.name = splitLine;
    else if (actProp == 1)cust.city = splitLine;
    else if (actProp == 2)cust.mail = splitLine;
    else if (actProp == 3)cust.telf = atoi(splitLine.c_str());
    actProp++;
}
//printf("Customer read: %s, %s, %s, %i\n",cust.name.c_str(), cust.city.c_str(), cust.mail.c_str(), cust.telf);

return cust;
}

int CompareTelf(string str1, string str2){
    Customer c1 = SplitLine(str1);
    Customer c2 = SplitLine(str2);

    if(c1.telf<c2.telf)return 1; //return 1 if 1st string its more important than second, otherwise, return -1
    else return -1;
}

struct Customer{
        string name;
        string city;
        string mail;
        long telf;
};

如果对代码有任何疑问,请直说!我尝试尽可能使用描述性的 varNames!

非常感谢。

【问题讨论】:

  • 如果您将重复次数推到极限并继续将数据拆分为单行文件,您将在每个合并阶段得到单行结果,因为在每个输入文件上都删除了一行排气。因此,递归地,所有合并的最终结果将是所有输入数据中的一行。那么你可能会自己发现错误......

标签: c++ file struct mergesort


【解决方案1】:

你的代码看起来不错,但它有几个缺陷和一个重要的遗漏。

其中一个小缺陷是缺少 Customer 结构的初始化 - 您没有为该结构提供构造函数,也没有对 cust 变量进行显式初始化。希望字符串成员被字符串类构造函数正确初始化,但long telf 可能会得到任何初始值。

另一个是在分割输入行时缺少格式检查。您确定每个输入行都具有相同的格式吗?如果有太多逗号的行(例如,名称中的逗号),则循环可能会错误地尝试将“电子邮件”数据分配给“telf”成员...
OTOH,如果逗号太少,“telf”成员可能保持未初始化状态,具有随机初始值...
与第一个缺陷一起,这个缺陷可能会导致输出数据的顺序不正确。

当您使用atoi 函数时会出现类似的问题:它返回int 但您的变量是long。我想您选择 long 类型是因为预期的值范围 - 如果是这样,将输入数据转换为 int 可能会截断大部分数据!我不确定atoi 在这种情况下会做什么,它可能会返回转换输入字符串的某些初始部分的结果,或者只返回零。这两个值都是错误的,会导致排序不正确,所以你最好改用atol

下一个问题是从两个输入文件中读取第一行。你不检查getline() 是否成功。如果输入文件为空,则对应的lineFile_num 字符串将为空,但endFil_num 不会反映这一点——它仍然是false。所以你再次去比较无效数据。

最后是主要问题。假设 file1 的内容“大于”(即:之后)整个 file2。然后存储在lineFile1 中的第一行导致CompareTelf() 一直返回-1。主循环将整个 file2 复制到输出中,然后...?最后的while() 循环以getline(file1,lineFile1) 开始,因此丢弃了file1 的第一行!
类似的结果发生在由记录 (A,C) 和 (B) 组成的文件中,要合并为 (A,B,C):首先读入 A 和 B,然后保存 A 并读入 C,然后是 B已保存并检测到文件 2 的结尾。然后while(getline(...)) 取消内存中的 C 并找到文件 1 的结尾,从而终止循环。记录 C 丢失。
通常,当主合并循环while(!endFil1 &amp;&amp; !endFil2) 耗尽一个文件时,另一个文件的第一个未保存的行将被丢弃。为避免这种情况,您需要存储第一次读取的结果:

endFil1 = ! getline(file1,lineFile1);
endFil2 = ! getline(file2,lineFile2);

然后,在主循环之后,使用未保存的行开始复制输入文件的尾部:

while(!endFil1) {
    mergeFile << lineFile1 << endl;
    endFil1 = !getline(file1,lineFile1);
}
while(!endFil2) {
    mergeFile << lineFile2 << endl;
    endFil2 = !getline(file2,lineFile2);
}

【讨论】:

  • 如果您将拆分例程推到了极限,以便合并单行文件,那么 - 在每个合并阶段丢失一行 - 您将得到一个单行文件每次合并。依此类推,直到顶层,这也将丢弃一行并为您留下一行“合并”输出。然后你就会注意到问题出在哪里。
猜你喜欢
  • 1970-01-01
  • 2021-08-29
  • 2015-02-26
  • 2011-01-22
  • 2013-06-06
  • 1970-01-01
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多