免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: flw
打印 上一主题 下一主题

【原创】超强版 Trim 横空出世! [复制链接]

论坛徽章:
0
21 [报告]
发表于 2004-03-02 20:39 |只看该作者

【原创】超强版 Trim 横空出世!

FH的代码和楼主的区别在于,用c=*str和*copied++=c来代替了*copied++=*str这一步,这实际上比起原来的代码反而多了一次赋值,而引用指针的次数却并不少。所以这段改过的代码效率不见得提高,反而降低了。
以前的帖子用到算法中有指针扫描到字符串结尾后又回溯的方式,这样对于最后一个非空字符后面的每个字符都做了一遍++和--运算。而楼主的帖子是做了一遍++和一遍赋值运算,效率应该都差不太多。
strlen和memmove我没研究过,不知效率如何,不敢妄言。

论坛徽章:
0
22 [报告]
发表于 2004-03-02 22:04 |只看该作者

【原创】超强版 Trim 横空出世!

我说一下我的意见:

用c来代替*str,是因为从汇编的角度判断*str需要至少两条指令,而直接判c的指令数要少,正因为有两次的*str判断和两次的*str赋值,况且如果做的再完善些,判断还远不止两个,所以才值得用c来替换*str。不服气的人可以把两段代码都执行一百万次,比较一下时间。

考虑C程序的效率,不能以C语句的多少来判断,要从汇编和指令周期的角度考虑问题,这是我的一点看法。

串处理指令的效率远远高于C的循环语句,我在自己的代码里使用的就是strlen和memmove、memcpy,其中memcpy的效率要高于memmove,这在man里面都有说明。

strlen的代码用串指令很容易实现:
xor ecx, ecx
repnz testsb
neg ecx
就这么简单!至于memcpy,我就不多说了。

论坛徽章:
0
23 [报告]
发表于 2004-03-02 22:08 |只看该作者

【原创】超强版 Trim 横空出世!

要不先把两段代码编译出来,看看目标文件的长度?

论坛徽章:
0
24 [报告]
发表于 2004-03-02 22:13 |只看该作者

【原创】超强版 Trim 横空出世!


  1. #include <stdio.h>;
  2. #include <ctype.h>;

  3. void str_trim ();

  4. int
  5. main ()
  6. {
  7.         char buf[1024] = "ab                cd         ";
  8.         str_trim (buf);
  9.         puts (buf);
  10.         return 0;
  11. }

  12. void
  13. str_trim (char *str)
  14. {
  15.         char *save = str;
  16.         char *b;

  17.         if (str == NULL)
  18.                 return;

  19.         if (isspace (*(b = str)))
  20.           {
  21.                   while (*b)
  22.                     {
  23.                             if (isspace (*b))
  24.                                     b++;
  25.                             else
  26.                                     break;
  27.                     }

  28.                   while (*b)
  29.                             *str++ = *b++;

  30.                   str--;
  31.                   while (isspace (*str))
  32.                         str--;

  33.                   str[1] = '\0';
  34.           }
  35.         else
  36.           {
  37.                   while (*b)
  38.                           b++;

  39.                   b--;
  40.                   while (isspace (*b))
  41.                           b--;
  42.                   b[1] = '\0';
  43.           }
  44.           return;
  45. }

复制代码


实现特点:
1、 采用 ansi c 中的宏 isspace
2、 处理了开始字节非"space" 的情况。
3、 仍然采用"回溯"的方式。优点是只对 开始的空白和最后的空白进行 isspace 判断。
4、 后面有很多空格的时候, 这个算法的效率仍值得推敲。

论坛徽章:
0
25 [报告]
发表于 2004-03-02 22:30 |只看该作者

【原创】超强版 Trim 横空出世!

BinBinNorth 与 FH 兄对 strlen 和 memcpy  的看法是有道理的。其实我很久以前就想做个测试, 不过要么没时间,要么就太懒,x86 不同指令的效率,总是使我很头疼)。先这么写了。

至于 c = *str 的优化,我把希望寄托在编译器的优化上了。

论坛徽章:
0
26 [报告]
发表于 2004-03-02 22:44 |只看该作者

【原创】超强版 Trim 横空出世!

呵呵,刚测了一百万次,没什么差别,分别是18秒和19秒,一千万次差别还稍微大一点。
测试用代码如下,编译时使用了-O选项:

  1. #include        <string.h>;

  2. #define        STRSZ        4096
  3. #define        TIMES        10000000

  4. extern void trim( char *str );

  5. main()
  6. {
  7.         int        i;
  8.         char        s[STRSZ];

  9.         for ( i = 0; i < TIMES; i ++ ) {
  10.                 memset( s, ' ', STRSZ - 1 );
  11.                 s[STRSZ - 1] = 0;
  12.                 trim( s );
  13.         }
  14. }
复制代码


测试结果如下(一千万次):

  1. c:
  2. real    2m49.856s
  3. user    2m49.838s
  4. sys     0m0.020s
  5. *str:
  6. real    3m7.069s
  7. user    3m7.059s
  8. sys     0m0.008s
复制代码

测试环境为:Red Hat Linux 8.0 on VMware 4.5.0-build 7174

论坛徽章:
0
27 [报告]
发表于 2004-03-03 08:43 |只看该作者

【原创】超强版 Trim 横空出世!

这是我去两头空格的trim,欢迎大家指正:
void trim(char *chr)
{
               int len;
               len = strlen(chr);
               while(chr[0] == ' ')
              {
                     for(int i=0;i<len;i++)
                          chr=chr[i+1];
                     len -= 1;
               }

               for(int i=len-1;chr == ' ';i--)
                    chr=0;
}

论坛徽章:
0
28 [报告]
发表于 2004-03-03 10:30 |只看该作者

【原创】超强版 Trim 横空出世!

我写的一个trim,带测试代码。
在sco unix,ibm aix4.3.windows上测试,效果比flw兄的好一点,尤其是在aix上。在sco上就很奇怪,优化比不优化还要慢,足见sco的烂。
缺点是对库函数的实现依赖太大。
  1. #include <stdio.h>;
  2. #include <string.h>;
  3. #include <memory.h>;
  4. #include <time.h>;

  5. void trim1( char *str )
  6. {
  7.         char *copied, *tail = NULL;

  8.         if ( str == NULL )
  9.                 return;

  10.         for( copied = str; *str; str++ )
  11.         {
  12.                 if ( *str != ' ' && *str != '\t' )
  13.                 {
  14.                         *copied++ = *str;
  15.                          tail = copied;
  16.                 }
  17.                 else
  18.                 {
  19.                          if ( tail )
  20.                                  *copied++ = *str;
  21.                 }
  22.         }

  23.         if ( tail )
  24.              *tail = 0;
  25.         else
  26.              *copied = 0;

  27.         return;
  28. }

  29. void trim2(char * str)
  30. {
  31.         char * start, * end;
  32.        
  33.         end=str + strlen(str)-1;
  34.         start=str;
  35.         for(; ((end>;=start)&&((*end==' ')||(*end=='\t'))); end--);
  36.         *(end+1)='\0';
  37.         for(; (start<=end)&&((*start==' ')||(*start=='\t')); start++);
  38.         if(start!=str)
  39.                 memmove(str, start, end-start+2);
  40. }

  41. int main()
  42. {
  43.         char buff[10000];
  44.         time_t time1, time2;
  45.         int i;
  46.        
  47.        
  48.         memset(buff, 'a', sizeof(buff));
  49.         buff[0]=' ';
  50.         buff[9998]=' ';
  51.         buff[9999]='\0';
  52.        
  53.        
  54.         time(&time1);
  55.         for(i=0; i<50000; i++)
  56.         {
  57.                 buff[0]=' ';
  58.                 buff[9997]='a';
  59.                 buff[9998]=' ';
  60.                 buff[9999]='\0';
  61.                 trim1(buff);
  62.         }
  63.         time(&time2);
  64.         printf("%d\n", time2-time1);
  65.        
  66.         time(&time1);
  67.         for(i=0; i<50000; i++)
  68.         {
  69.                 buff[0]=' ';
  70.                 buff[9997]='a';
  71.                 buff[9998]=' ';
  72.                 buff[9999]='\0';
  73.                 trim2(buff);
  74.         }
  75.         time(&time2);
  76.         printf("%d\n", time2-time1);
  77.        
  78.         getchar();

  79.         return 0;
  80. }
复制代码

论坛徽章:
0
29 [报告]
发表于 2004-03-03 11:30 |只看该作者

【原创】超强版 Trim 横空出世!

[quote="guixin"][/quote]
用chr[i]这种方式效率肯定比用指针慢很多。

论坛徽章:
0
30 [报告]
发表于 2004-03-03 11:37 |只看该作者

【原创】超强版 Trim 横空出世!

库函数的实现各个编译器可能不同,比如strlen这样的字符串操作,可能是在底层用汇编的串操作实现的,所以效率高也不足为奇,另外如果真的是用汇编实现的话,这么比较似乎也不公平,总而言之,flw的算法思想是很不错的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP