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语句,这完全没必要,何必还调用一个函数呢,申请栈释放栈很浪费时间,然后我们去掉这个函数,直接在别的函数里面用它里面的语句。

我们再来看

  1. for (int i = 0; i < replacement->Length; i++) {
  2.         data = insertChar(data, loc+i, replacement, i);
  3.         // data->Insert(loc + i, replacement->Substring(i, 1));
  4.     }

这个也没必要,何必一个一个的插入呢?整体插入就算了。因而可以改为

  1. return data->Insert(loc,replacement);

对于indeof函数,占的时间实在太多,是该解决一下它,在原函数中间是这样的:

  1. for (loc = data->IndexOf(pattern, 0); loc >= 0;
  2.                 loc = data->IndexOf(pattern, 0)) {
  3.                 // replace word
  4.                 data = replace_word(data, loc, pattern->Length, replacement);
  5.             }   

没必要总是从第一个找起吧!起先我想的是从上一次查找的结束的下一个位置开始查找,但这样有一个问题。例如我们用dd替换cd,有一个字符串为cccd,第一次替换后为ccdd,不应该只是往后找,因为此时前面也出现了cd,故而在这里我们可以从新得到的loc 前 pattern->length处开始查找,再往前开始找没意义。在这里还就是pattern->Length最好在外面用一个变量代替,如pl,放置循环次次都计算pattern->Length(你可能认为编译器足够聪明,但我们不敢保证它在这里“敢”优化,毕竟pattern是个指针,随时可以变,还是我们替他提早优化,参考《深入理解计算机系统》)。

故而这段程序改为:

 

  1. int location = 0;
  2.         int pl = pattern->Length;
  3.         // find every occurrence of pattern:
  4.         for (loc = data->IndexOf(pattern, 0); loc >= 0;
  5.             loc = data->IndexOf(pattern, location)) {
  6.                 // replace word
  7.                 int dis = loc - pl;
  8.                 if (dis >= 0)
  9.                 {
  10.                     location = dis;
  11.                 } 
  12.                 else
  13.                 {
  14.                     location = 0;
  15.                 }
  16.                 data = replace_word(data, loc, pl, replacement);

改过的程序为:

  1. #include <iostream>
  2. using namespace std;
  3. using namespace System;
  4. using namespace System::IO;
  5. using namespace System::Text;
  6. //String* insertChar(String *data, int loc, String *replacement, int i) {
  7. //  return data->Insert(loc, replacement->Substring(i, 1));
  8. //}
  9. String* replace_word(String* data, int loc, int length, String* replacement) {
  10.     // delete the pattern string from loc:
  11.     data = data->Remove(loc, length);
  12.     // insert each character of the replacement string:
  13.     //for (int i = 0; i < replacement->Length; i++) {
  14.     //  data = insertChar(data, loc+i, replacement, i);
  15.     //  // data->Insert(loc + i, replacement->Substring(i, 1));
  16.     //}
  17.     return data->Insert(loc,replacement);
  18.     //->Insert(loc,replacement)
  19. }
  20. String* string_subst(String *data, String *pattern, String *replacement) {
  21.     try {
  22.         int loc;
  23.         int location = 0;
  24.         int pl = pattern->Length;
  25.         // find every occurrence of pattern:
  26.         for (loc = data->IndexOf(pattern, 0); loc >= 0;
  27.             loc = data->IndexOf(pattern, location)) {
  28.                 // replace word
  29.                 int dis = loc - pl;
  30.                 if (dis >= 0)
  31.                 {
  32.                     location = dis;
  33.                 } 
  34.                 else
  35.                 {
  36.                     location = 0;
  37.                 }
  38.                 data = replace_word(data, loc, pl, replacement);
  39.         }   
  40.         return data;
  41.     } catch (Exception *e) {
  42.         Console::WriteLine("Error in substitute ");
  43.         Console::WriteLine(e->ToString());
  44.         return data;
  45.     }
  46. }
  47. String* batch_subst(String *data, const char* subs_filename) {
  48.     try {
  49.         String *subs_file = new String(subs_filename);
  50.         StreamReader *subs_reader = new StreamReader(subs_file);
  51.         String *pattern, *replacement, *separator;
  52.         while (subs_reader->Peek() >= 0) {
  53.             pattern = subs_reader->ReadLine();
  54.             replacement = subs_reader->ReadLine();
  55.             separator = subs_reader->ReadLine();
  56.             data = string_subst(data, pattern, replacement);
  57.         }
  58.         return data;
  59.     } catch(Exception* e ) {
  60.         Console::WriteLine( "Error in do_substitutions ");
  61.         Console::WriteLine( e->ToString());
  62.         return data;
  63.     }
  64. }
  65. void process_file(const char* filename, const char* subs_filename) {
  66.     StreamReader *reader;
  67.     StreamWriter *writer;
  68.     String *file = new String(filename);
  69.     try {
  70.         reader = new StreamReader( file );
  71.         String *data = reader->ReadToEnd();
  72.         data = batch_subst(data, subs_filename);
  73.         reader->Close();
  74.         // write the data
  75.         writer = new StreamWriter(file, false);
  76.         writer->Write(data);
  77.         writer->Close();
  78.     }  catch(Exception* e) {
  79.         Console::WriteLine( "Error while processing file ");
  80.         Console::WriteLine( e->ToString());
  81.     }
  82. }
  83. int main(int argc, char *argv[]) {  
  84.     if (argc < 3) {
  85.         cout << "Not enough input arguments" << endl;
  86.         cout << "Usage: substitute subs-file src1 src2 ..." << endl;
  87.     } else {
  88.         for (int i = 2; i < argc; i++) {
  89.             process_file(argv[i], argv[1]);
  90.         }
  91.     }
  92.     return 0;
  93. }

我还准备优化那个reader->Close();writer->Close();没必要每次都关闭。但尝试了一下,最终失败。希望看过此文章的人不吝赐教,多多指导,共同学习。

 

posted on 2008-12-01 22:55  NULL00  阅读(2717)  评论(1编辑  收藏  举报

导航