百度面试题及我的解答(5)-0 优化性能

本次的主题是优化TraverseTbl

代码主要包括两部分:

         1. 一部分是把单词从文件读入到Hash表的Add部分。

         2. 第二部分是遍历hash表,找出所有的变位词,并输出。

 

下表是主要时间消耗函数在step5函数,dict4输入时性能统计数据(VS2005 Team Suit)。从图中可以看出,TraverseTbl函数消耗的时间最多,所以本次优化的主题就在TraverseTbl

 

 调用次数已用包含时间应用程序包含时间
HashMethod1::Add(char *)1158441.1581341.15813
HashMethod1::TraverseTbl(void (*)(class WORD_NODE *,class std::basic_ostream<char,struct std::char_traits<char> > &),class std::basic_ostream<char,struct std::char_traits<char> > &)1246.404109246.404109
std::basic_istream<char,struct std::char_traits<char> >::getline(char *,int)1158410.34587210.345872

 

首先说明一下从step4->step5的主要变化。

1. 在step4的基础上修改了输出函数。对于变位词,不再输出所有词,而是每个单词只输出一次。

2. step4和step5使用的都是vector来保存临时使用的变位词列表(用于检索这个词是否已经出现过)。

 

Step5使用样本dict4的性能测试数据。这里只摘录了TraverseTbl 函数的性能数据。

仔细阅读下表,可以发现vector各种操作占用了大量的CPU时间,看来在这里STL成为了性能瓶颈了。

 已用包含时间应用程序包含时间
Step5TraverseProcess(class WORD_NODE *,class std::basic_ostream<char,struct std::char_traits<char> > &)243.778101243.778101
@_RTC_CheckStackVars@80.1228640.122864
__RTC_CheckEsp0.0027780.002778
std::_Vector_const_iterator<char *,class std::allocator<char *> >::operator<(class std::_Vector_const_iterator<char *,class std::allocator<char *> > const &)2.9927182.992718
std::_Vector_const_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::operator<(class std::_Vector_const_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> > const &)2.5465262.546526
std::_Vector_iterator<char *,class std::allocator<char *> >::_Vector_iterator<char *,class std::allocator<char *> >(void)0.4390950.439095
std::_Vector_iterator<char *,class std::allocator<char *> >::~_Vector_iterator<char *,class std::allocator<char *> >(void)16.54360216.543602
std::_Vector_iterator<char *,class std::allocator<char *> >::operator*(void)0.9144710.914471
std::_Vector_iterator<char *,class std::allocator<char *> >::operator++(int)21.6999221.69992
std::_Vector_iterator<char *,class std::allocator<char *> >::operator=(class std::_Vector_iterator<char *,class std::allocator<char *> > const &)3.5134513.513451
std::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >(void)0.1285640.128564
std::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::~_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >(void)27.02592127.025921
std::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::operator*(void)2.3361242.336124
std::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::operator++(int)37.6102437.61024
std::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::operator=(class std::_Vector_iterator<class WORD_NODE *,class std::allocator<class WORD_NODE *> > const &)3.3707323.370732
std::operator<<<struct std::char_traits<char> >(class std::basic_ostream<char,struct std::char_traits<char> > &,char const *)17.05477617.054776
std::vector<char *,class std::allocator<char *> >::~vector<char *,class std::allocator<char *> >(void)3.1718333.171833
std::vector<char *,class std::allocator<char *> >::begin(void)6.044066.04406
std::vector<char *,class std::allocator<char *> >::end(void)10.86284810.862848
std::vector<char *,class std::allocator<char *> >::push_back(char * const &)27.36062327.360623
std::vector<char *,class std::allocator<char *> >::vector<char *,class std::allocator<char *> >(void)0.6923440.692344
std::vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::~vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >(void)0.9105660.910566
std::vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::begin(void)5.3921345.392134
std::vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::end(void)12.8719712.87197
std::vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::push_back(class WORD_NODE * const &)33.51650533.516505
std::vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >::vector<class WORD_NODE *,class std::allocator<class WORD_NODE *> >(void)0.249840.24984
THUNK:strcmp1.5513011.551301

 

在前面分析的基础上为step6做优化:step6放弃了所有的STL,使用了原生数组来保存临时使用的变位词列表,代码复杂了很多。

step6,使用dict4(和上面的数据使用同样的输入样本)输入的性能数据请见下表。从数据可以看出TraverseTbl使用时间大幅减少。已经不再是整个程序的性能瓶颈。

 已用包含时间应用程序包含时间
HashMethod1::TraverseTbl(void (*)(class WORD_NODE *,class std::basic_ostream<char,struct std::char_traits<char> > &),class std::basic_ostream<char,struct std::char_traits<char> > &)10.0268910.02689
std::basic_ifstream<char,struct std::char_traits<char> >::`vbase destructor'(void)0.0022750.002275
std::basic_ifstream<char,struct std::char_traits<char> >::basic_ifstream<char,struct std::char_traits<char> >(void)0.0037450.003745
std::basic_ifstream<char,struct std::char_traits<char> >::close(void)0.0383950.038395
std::basic_ifstream<char,struct std::char_traits<char> >::is_open(void)0.0001330.000133
std::basic_ifstream<char,struct std::char_traits<char> >::open(char const *,int,int)0.0901270.090127
std::basic_istream<char,struct std::char_traits<char> >::getline(char *,int)14.46054414.460544
std::basic_ofstream<char,struct std::char_traits<char> >::`vbase destructor'(void)0.0092480.009248
std::basic_ofstream<char,struct std::char_traits<char> >::basic_ofstream<char,struct std::char_traits<char> >(char const *,int,int)0.3083740.308374
std::basic_ofstream<char,struct std::char_traits<char> >::close(void)1.2348041.234804
std::basic_ostream<char,struct std::char_traits<char> >::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > & (*)(class std::basic_ostream<char,struct std::char_traits<char> > &))0.1682450.168245
std::basic_ostream<char,struct std::char_traits<char> >::operator<<(unsigned long)1.054691.05469
std::ios_base::eof(void)0.5812690.581269

 

再看TraverseTbl的性能数据,可以看出修改后主要的CPU时间都消耗在了输出了。这里优化的余地很小了。

关于标准库ostream输出,有一个小的优化技巧:

      C++ Primter中说"endl“会触发输出缓冲区flush,所以在换行的时候使用"/n“在输出密集时可以极大的减少CPU时间。

 调用次数已用包含时间应用程序包含时间
HashMethod1::TraverseTbl(void (*)(class WORD_NODE *,class std::basic_ostream<char,struct std::char_traits<char> > &),class std::basic_ostream<char,struct std::char_traits<char> > &)110.0268910.02689
__RTC_CheckEsp5510.0000780.000078
Step6TraverseProcess(class WORD_NODE *,class std::basic_ostream<char,struct std::char_traits<char> > &)5507.8642887.864288
@_RTC_CheckStackVars@85500.0072520.007252
__RTC_CheckEsp5500.000130.00013
std::operator<<<struct std::char_traits<char> >(class std::basic_ostream<char,struct std::char_traits<char> > &,char const *)60486.3603576.360357
THUNK:memset11000.0707640.070764
THUNK:strcmp460760.7020090.702009

 

 

最后给出GetTickCount记录的优化前后的性能数据比较。

 step5step6
第一次第二次第一次第二次
添加单词到Hash表(Add,getline,sort)1061106111701061
遍历hash表输出变位词49774961281249
     
step5: 使用标准库的vector保存所有零时的变位词,使用iterator遍历变位词表
step6: 使用普通数组保存所有零时的变位词,数组遍历变位词表 

 

附: step5 & step6的代码单独发文给出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值