我的老师说我可以为()循环优化这个,但我看不出怎样,任何帮助都会很棒
void vowels(char strng[])
{
int i, j, word_len, vowels_len, vowel_count;
char vowels[] = "aeiouAEIOU";
word_len = strlen(strng);
vowels_len = strlen(vowels);
vowel_count = 0;
for (i = 0; i < word_len; ++i) {
for (j = 0; j < vowels_len; ++j) {
if (strng[i] == vowels[j]) {
++vowel_count;
break;
}
}
}
printf("%s: %d vowels\n", strng, vowel_count);
}
答案 0 :(得分:5)
一种方法是完全删除嵌套循环,将其替换为将字符代码映射到表示char
是否为元音的标志的数组:
int isVowel[256] = {0};
for (int i = 0 ; vowels[i] != '\0' ; i++) {
isVowel[(unsigned char)vowels[i]] = 1;
}
现在可以按如下方式优化主循环:
for (int i = 0; i != word_len ; i++) {
vowel_count += isVowel[(unsigned char)string[i]];
}
您可以使用switch
声明获得相似的效果:
for (int i = 0; i != word_len ; i++) {
switch(string[i]) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
vowel_count ++;
break;
}
}
答案 1 :(得分:0)
比Dasblinkenlight更简单的优化是:
git push -v origin master
(char vowels[] = "AEIOU";
vowels_len = sizeof(vowels)-1;
...
for (char c=strng[i]&~32, j = 0; j < vowels_len; ++j) {
if (c == vowels[j]) {
是ascii中的toupper。)
答案 2 :(得分:0)
不确定你的老师是否会考虑这种作弊行为,但这是寻找比使用2个嵌套for循环更优化的元音的一种可能方法。
char *pos;
int vowel_count=0;
pos=strng;
while(pos)
{
pos=strpbrk(pos,"aeiouAEIOU");
if(pos)
{
vowel_count++;
pos++;
}
}
答案 3 :(得分:0)
为了优化代码,您必须首先意识到什么是瓶颈。在算法级别,您有以下基本性能问题:
strlen
遍历整个字符串以搜索空终止符,因此您遍历相同的字符串strng
两次。这是低效的 - 最好的方法是在检查数据的同时检查空终止。"aeiouAEIOU"
是一个常量,因此您可以在编译时知道它的大小。无需使用strlen()在运行时计算此值。您可以使用sizeof
代替,这在编译时进行评估。您还有一个主要错误,即该函数不会返回结果。
“天真”手动优化的第一步是这样的:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
int vowels(const char str[])
{
const char VOWEL_LOOKUP[] = "AEIOU";
int vowel_count = 0;
for(; *str != '\0'; str++)
{
char ch = toupper(*str);
for(size_t i=0; i<sizeof(VOWEL_LOOKUP)-1; i++)
{
if(ch == VOWEL_LOOKUP[i])
{
vowel_count++;
break;
}
}
}
return vowel_count;
}
int main (void)
{
const char str[] = "Stack Overflow"; // 4 vowels
printf("%s: %d vowels\n", str, vowels(str));
}
在高级别上,您将查看算法所需的分支数量,因为这些分支会最大程度地降低性能,阻止CPU的分支预测。
然后,您可以考虑使用查找表替换内部循环。这可能会也可能不会提高性能 - 但至少它会使性能具有确定性。此时你可能会开始牺牲可读性,所以你不应该进一步优化,除非这是一个已知的瓶颈。
查找表版本可能看起来像这个邪恶的,不推荐的代码,它利用了符号表通常按字母顺序列出字母的事实(EBCDIC没有,所以这不会编译在各种疯狂的遗产上系统)。
int vowels(const char str[])
{
_Static_assert('Z' - 'A' == 25, "Weird symbol table."); // compile-time sanity check
const bool VOWEL_LOOKUP['U'-'A'+1] = // compromise between sacrificing RAM or speed
{
['A'-'A'] = true,
['E'-'A'] = true,
['I'-'A'] = true,
['O'-'A'] = true,
['U'-'A'] = true,
};
int vowel_count = 0;
for(; *str != '\0'; str++)
{
char ch = toupper(*str);
if(ch >= 'A' && ch <= 'U') // always 2 branches instead of 5
{ // but comes with a bit of calculation overhead:
ch -= 'A';
vowel_count += (int)VOWEL_LOOKUP[(size_t)ch];
}
}
return vowel_count;
}
这不一定更快......总是以它为基准。
答案 4 :(得分:0)
最快的事情。
void ultravowulator(const char strng[])
{
char vowels[] = "aeiouAEIOU";
int vowelscnt = strlen(vowels);
int vocabular[256] = {0};
for(; *strng != '\0'; strng++) {
vocabular[*strng]++;
}
int total = 0;
for (int i = 0; i < vowelscnt; i++){
total += vocabular[vowels[i]];
}
cout << total << endl;
}
main()
{
char word[] = "Stack overflow";
ultravowulator(word);
}