我正在写一个非常简单的函数,它计算某个字符在给定字符串中出现的次数。我有一个工作功能,但想知道是否有更有效或首选的方法来做到这一点。
这是功能:
size_t strchroc(const char *str, const char ch)
{
int c = 0, i = 0;
while(str[i]) if(str[i++] == ch) c++;
return c;
}
我个人想不出任何方法可以让这段代码更有效率。如果有人知道如何使这个功能更有效率,那就是想知道(仅仅是为了学习)。
(从速度和使用最少资源的角度来看,效率很高)。
答案 0 :(得分:5)
首先,除非您的功能真的时间敏感,否则请勿尝试过度优化。只需使用您提供的那个,因为它很容易验证是否正确,并且它不会试图变得聪明只是为了它。
如果功能真的需要快速,那么有很多方法可以更好地优化它。很多很多方面。它们中的一些要么期望或假设你所拥有的字符串的特定存储器布局(例如,它们被分配在字边界上,并且分配也总是填充到字边界)。因此,您需要小心,因为算法可能会对处理器,编译器和内存分配器的某些组合起作用,而对其他组合则会失败。
只是为了它,我会列出一些加速角色计数器的可能方法:
等等。
但我真的,真的建议如果你遇到现实世界的问题,你会坚持使用那个。如果这是一个玩具问题,并且您正在优化它的乐趣,请继续。
循环剃须是一种学习CPU和指令集的有趣方式,但对于99.999999%的编程任务来说,这是不值得的。
答案 1 :(得分:2)
您可以使用指针迭代字符串,只需稍加努力,每个字符只使用*
一次:
size_t strchroc(const char *str, const char ch)
{
size_t c = 0;
char n;
while ((n=*str++), ((n==ch)? ++c : 0), n)
;
return c;
}
并不是说编译器无法优化你的代码,只是为了好玩。
答案 2 :(得分:1)
在使用您的功能之前,您应该使用strchr()
(或memchr()
,如果您知道长度)。如果匹配,您可以从第一个匹配字符的位置开始,然后从那里开始。
除非你的字符串非常短,或者它很早就匹配,否则这应该快得多。
答案 3 :(得分:0)
你可以摆脱变量i
。
size_t strchroc(const char *str, const char ch){
size_t c = 0;
while(*str != '\0') {
if(*str == ch) c++;
str++;
}
return c;
}
答案 4 :(得分:0)
size_t count_the_string(const char *str, const char ch){
size_t cnt ;
for(cnt=0; *str; ) {
cnt += *str++ == ch;
}
return cnt;
}
对于等效的do { ...} while();
变体,GCC生成的代码没有条件跳转(当然除了循环的跳转),与@hakattack的解决方案相当。
size_t count_the_string2(const char *str, const char ch){
size_t cnt=0 ;
do {
cnt += *str == ch;
} while (*str++);
return cnt;
}
答案 5 :(得分:0)
在快速低质量基准测试之后,我最终得到了任意长度的字符串。
在巨大的字符串(100M +)上,它没有表现出太大的差异,但在较短的字符串(句子,普通文本文件等)上,改善率约为25%。
unsigned int countc_r(char *buf, char c)
{
unsigned int k = 0;
for (;;) {
if (!buf[0]) break;
if ( buf[0] == c) ++k;
if (!buf[1]) break;
if ( buf[1] == c) ++k;
if (!buf[2]) break;
if ( buf[2] == c) ++k;
if (!buf[3]) break;
if ( buf[3] == c) ++k;
buf += 4;
}
return k;
}