问题描述
我在技术测试中被问到这个问题。
他们询问如何将字符串中的 ' ' 更改为 '_'。
我认为他们不想要共同的答案。像这样(我可以保证)
void replaceChar(char originalStr[],size_t strLength,char originalChar,char newChar
{
for(size_t i = 0 ; i < strLength ; i++)
{
if(originalStr[i] == originalChar)
{
originalStr[i] = newChar ;
}
}
}
所以我是这样回答的。使用单词。 (其实我没有写代码,他们只是想解释怎么做)
我认为将字符串的每个 8 字节(64 位操作系统)与掩码 8 字节进行比较。
如果它们相等,则一次替换 8byte。
当 cpu 读取小于 WORD 的数据时,cpu 应该做清除剩余位的操作。
它很慢。所以我尝试使用 WORD 来比较字符。
void replaceChar(char originalStr[],char newChar //
{
size_t mask = 0;
size_t replaced = 0;
for(size_t i = 0 ; i < sizeof(size_t) ; i++)
{
mask |= originalChar << i;
replaced |= newChar << i;
}
for(size_t i = 0 ; i < strLength ; i++)
{
// if 8 byte data equal with 8 byte data filled with originalChar
// replace 8 byte data with 8 byte data filled with newChar
if(i % sizeof(size_t) == 0 &&
strLength - i > sizeof(size_t) &&
*(size_t*)(originalStr + i) == mask)
{
*(size_t*)(originalStr + i) = replaced;
i += sizeof(size_t);
continue;
}
if(originalStr[i] == originalChar)
{
originalStr[i] = newChar ;
}
}
}
有没有更快的方法??
解决方法
在通往快速之路的第一件事就是正确。原始提案的问题在于 sizeof(s)
应该是 strlen(s)
的缓存值。那么明显的问题是,这种方法扫描字符串两次——首先找到终止字符,然后是要替换的字符。
这应该由已知长度的数据结构或数据结构来解决,有足够的保证多余数据,以便可以一次处理多个字节而不会出现未定义的行为。
一旦解决了这个问题(OP 已经被编辑以解决这个问题),建议的扫描 8 个字节的数据的所有字节相同的方法的问题是通用案例确实有 8 个连续的字符,但也许仅 7. 在所有这些情况下,都需要扫描同一区域两次(在扫描字符串终止字符的基础上)。
如果字符串长度未知,最好使用低级方法:
while (*ptr != 0) {
if (*ptr == search_char) {
*ptr = replace_char;
}
++ptr;
}
如果字符串长度已知,最好使用库方法std::replace
,或者低级对应
for (auto i = 0; i < size; ++i) {
if (str[i] == search_char) {
str[i] = replace_char;
}
}
任何体面的编译器都能够自动向量化这一点,尽管编译器可能会生成比预期更多的内核(一个内核用于小尺寸,一个用于中间,另一个用于处理 32 或 64 字节的块)。