如果我有一个以二进制形式表示整数的字符串,例如
1101101
我想将其循环右移以获得
1110110
我想到的一种方法是将字符串转换为int
并使用(摘自wikipedia)
// https://stackoverflow.com/a/776550/3770260
template <typename INT>
#if __cplusplus > 201100L // Apply constexpr to C++ 11 to ease optimization
constexpr
#endif // See also https://stackoverflow.com/a/7269693/3770260
INT rol(INT val, size_t len) {
#if __cplusplus > 201100L && _wp_force_unsigned_rotate // Apply unsigned check C++ 11 to make sense
static_assert(std::is_unsigned<INT>::value,
"Rotate Left only makes sense for unsigned types");
#endif
return (val << len) | ((unsigned) val >> (-len & (sizeof(INT) * CHAR_BIT - 1)));
}
但是,如果字符串由10 ^ 6 char
组成,则此操作不起作用,因为整数表示甚至超过了__int64
的范围。
在那种情况下,我可以通过遍历字符串来考虑解决方案
//let str be a char string of length n
char temp = str[n - 1];
for(int i = n - 1; i > 0; i--)
{
str[i] = str[i - 1];
}
str[0] = temp;
该解决方案在O(n)
中运行,这是由于在字符串n的长度上存在循环。我的问题是,对于大型二进制字符串,是否有更有效的方法来实现循环移位?
输入和输出均为std::string
答案 0 :(得分:1)
您必须以一种或另一种方式移动内存,因此您提出的解决方案要尽可能快。
您还可以使用标准的std::string
函数:
str.insert(str.begin(), str[n - 1]);
str.erase(str.end() - 1);
或memmove
或memcpy
(我实际上不建议这样做,这是出于争论)
char temp = str[n - 1];
memmove(str.data() + 1, str.data(), n - 1);
str[0] = temp;
请注意,memmove
的外观可能更快,但这与循环本质上是一样的。它正在逐字节移动字节,只是封装在其他函数中。这种方法对于更大的数据块(大小为1000字节或更大)可能更快,因为CPU已优化为移动大块内存。但是您将无法测量10或20个字节的任何差异。
此外,当编译器看到for
循环时,很可能会运行其他优化,它意识到您正在移动内存并选择最佳选项。
编译器还擅长处理std::string
方法。这些是常见的操作,编译器知道处理它的最佳方法。