SSD6中Exercise4 (substitute.cpp) 答案解析
今天终于把Exercise4搞定了,昨天大约优化了0.38秒,今天优化了0.52秒,跨越了一大步。
在我们未加任何修饰执行此代码时,其执行后所用时间如图(摘抄主要):
Function | Callee Exclusive Time |
main | 1.495306 |
IndexOf( String, int32 ) |
0.771013 |
insertChar( String, int32, String, int32 ) | 0.444054 |
我们发现insertChar()函数里面就一条return语句,这完全没必要,何必还调用一个函数呢,申请栈释放栈很浪费时间,然后我们去掉这个函数,直接在别的函数里面用它里面的语句。
我们再来看
- for (int i = 0; i < replacement->Length; i++) {
- data = insertChar(data, loc+i, replacement, i);
- // data->Insert(loc + i, replacement->Substring(i, 1));
- }
这个也没必要,何必一个一个的插入呢?整体插入就算了。因而可以改为
- return data->Insert(loc,replacement);
对于indeof函数,占的时间实在太多,是该解决一下它,在原函数中间是这样的:
- for (loc = data->IndexOf(pattern, 0); loc >= 0;
- loc = data->IndexOf(pattern, 0)) {
- // replace word
- data = replace_word(data, loc, pattern->Length, replacement);
- }
没必要总是从第一个找起吧!起先我想的是从上一次查找的结束的下一个位置开始查找,但这样有一个问题。例如我们用dd替换cd,有一个字符串为cccd,第一次替换后为ccdd,不应该只是往后找,因为此时前面也出现了cd,故而在这里我们可以从新得到的loc 前 pattern->length处开始查找,再往前开始找没意义。在这里还就是pattern->Length最好在外面用一个变量代替,如pl,放置循环次次都计算pattern->Length(你可能认为编译器足够聪明,但我们不敢保证它在这里“敢”优化,毕竟pattern是个指针,随时可以变,还是我们替他提早优化,参考《深入理解计算机系统》)。
故而这段程序改为:
- int location = 0;
- int pl = pattern->Length;
- // find every occurrence of pattern:
- for (loc = data->IndexOf(pattern, 0); loc >= 0;
- loc = data->IndexOf(pattern, location)) {
- // replace word
- int dis = loc - pl;
- if (dis >= 0)
- {
- location = dis;
- }
- else
- {
- location = 0;
- }
- data = replace_word(data, loc, pl, replacement);
改过的程序为:
- #include <iostream>
- using namespace std;
- using namespace System;
- using namespace System::IO;
- using namespace System::Text;
- //String* insertChar(String *data, int loc, String *replacement, int i) {
- // return data->Insert(loc, replacement->Substring(i, 1));
- //}
- String* replace_word(String* data, int loc, int length, String* replacement) {
- // delete the pattern string from loc:
- data = data->Remove(loc, length);
- // insert each character of the replacement string:
- //for (int i = 0; i < replacement->Length; i++) {
- // data = insertChar(data, loc+i, replacement, i);
- // // data->Insert(loc + i, replacement->Substring(i, 1));
- //}
- return data->Insert(loc,replacement);
- //->Insert(loc,replacement)
- }
- String* string_subst(String *data, String *pattern, String *replacement) {
- try {
- int loc;
- int location = 0;
- int pl = pattern->Length;
- // find every occurrence of pattern:
- for (loc = data->IndexOf(pattern, 0); loc >= 0;
- loc = data->IndexOf(pattern, location)) {
- // replace word
- int dis = loc - pl;
- if (dis >= 0)
- {
- location = dis;
- }
- else
- {
- location = 0;
- }
- data = replace_word(data, loc, pl, replacement);
- }
- return data;
- } catch (Exception *e) {
- Console::WriteLine("Error in substitute ");
- Console::WriteLine(e->ToString());
- return data;
- }
- }
- String* batch_subst(String *data, const char* subs_filename) {
- try {
- String *subs_file = new String(subs_filename);
- StreamReader *subs_reader = new StreamReader(subs_file);
- String *pattern, *replacement, *separator;
- while (subs_reader->Peek() >= 0) {
- pattern = subs_reader->ReadLine();
- replacement = subs_reader->ReadLine();
- separator = subs_reader->ReadLine();
- data = string_subst(data, pattern, replacement);
- }
- return data;
- } catch(Exception* e ) {
- Console::WriteLine( "Error in do_substitutions ");
- Console::WriteLine( e->ToString());
- return data;
- }
- }
- void process_file(const char* filename, const char* subs_filename) {
- StreamReader *reader;
- StreamWriter *writer;
- String *file = new String(filename);
- try {
- reader = new StreamReader( file );
- String *data = reader->ReadToEnd();
- data = batch_subst(data, subs_filename);
- reader->Close();
- // write the data
- writer = new StreamWriter(file, false);
- writer->Write(data);
- writer->Close();
- } catch(Exception* e) {
- Console::WriteLine( "Error while processing file ");
- Console::WriteLine( e->ToString());
- }
- }
- int main(int argc, char *argv[]) {
- if (argc < 3) {
- cout << "Not enough input arguments" << endl;
- cout << "Usage: substitute subs-file src1 src2 ..." << endl;
- } else {
- for (int i = 2; i < argc; i++) {
- process_file(argv[i], argv[1]);
- }
- }
- return 0;
- }
我还准备优化那个reader->Close();writer->Close();没必要每次都关闭。但尝试了一下,最终失败。希望看过此文章的人不吝赐教,多多指导,共同学习。
可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明