无论方向如何,都从一个整数循环到另一个整数,开销最小

use*_*342 2 c++ algorithm

假设我有两个无符号整数:

size_t A, B;
Run Code Online (Sandbox Code Playgroud)

它们加载了一些随机数,A可能比B大,等于或小.我想从A循环到B.但是,比较和增量都取决于哪个更大.

for (size_t i = A; i <= B; ++i) //A <= B
for (size_t i = A; i >= B; --i) //A >= B
Run Code Online (Sandbox Code Playgroud)

显而易见的蛮力解决方案是将这些嵌入if语句中:

if (A <= B)
{
 for (size_t i = A; i <= B; ++i) ...
}
else
{
 for (size_t i = A; i >= B; --i) ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,我必须 A 循环 B,所以我不能有两个中间整数,并将A和B放入右侧插槽,然后进行相同的比较和增量.在"A更大"的情况下,我必须减少,而相反的必须增加.

我将要有许多嵌套循环,需要相同的设置,这意味着每个if/else都会有一个函数调用,我必须传递大量的变量,或者另一个if/else与另一个if/else等.

在不牺牲速度的情况下避免这种情况有什么棘手的捷径吗?功能指针和东西在一个紧凑的,经常重复的循环中听起来非常痛苦.有一些疯狂的模板解决方案吗?

pad*_*ddy 7

我的错误,最初是误解了这个问题.

为了使一个包容性的循环,从AB,你有一个棘手的情况.你需要循环过去 B.所以你在循环之前计算出这个值.我在for循环中使用了逗号运算符,但为了清晰起见,你总是可以把它放在外面.

int direction = (A < B) ? 1 : -1;
for( size_t i = A, iEnd = B+direction; i != iEnd; i += direction ) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果你不介意修改AB,你可以改为(A用作循环变量):

for( B+=direction, A != B; A += direction ) {

}
Run Code Online (Sandbox Code Playgroud)

我玩了一下......当涉及到函数指针时,不知道内联规则是什么,或者这是否更快,但它无论如何都是一个练习.=)

inline const size_t up( size_t& val ) { return val++; }
inline const size_t down( size_t& val ) { return val--; }

typedef const size_t (*FnIncDec)( size_t& );

inline FnIncDec up_or_down( size_t A, size_t B )
{
    return (A <= B) ? up : down;
}

int main( void )
{
    size_t A = 4, B = 1;
    FnIncDec next = up_or_down( A, B );

    for( next(B); A != B; next(A) ) {
        std::cout << A << endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

对此:

这对于A = 0,B = UINT_MAX(反之亦然)的情况不起作用

那是正确的.问题是由于溢出而导致的初始值iiEnd变为相同.要处理它,你可以使用do->while循环.这将删除初始测试,这是多余的,因为您将始终至少执行一次循环体...通过删除第一个测试,您第一次迭代超过终止条件.

size_t i = A;
size_t iEnd = B+direction;

do {
    // ...
    i += direction;
} while( i != iEnd );
Run Code Online (Sandbox Code Playgroud)

  • 这会导致我在某些情况下从B循环到A. 它必须是A到B. (2认同)

Che*_*Alf 5

size_t const delta = size_t(A < B? 1 : -1);
size_t i = A;
for( ;; )
{
    // blah

    if( i == B ) { break; }
    i += delta;
}
Run Code Online (Sandbox Code Playgroud)