我创建了一个包含std :: vector的堆栈类。我编写了像pop()和exch()之类的堆栈操作,如
int Stack::pop()
{
if (v.size() < 0)
throw("Error : Stack Underflow");
int tos = v.back();
stack.erase(v.end()-1);
return tos;
}
void Stack::exch() // Exchange top 2 element
{
if (v.size() < 2)
throw("Error : Stack Underflow");
size_t n = v.size();
int tmp = v[n-1];
v[n-1] = v[n-2];
v[n-2] = tmp;
}
我的应用程序包含很多'pop()'和'exch()'运作。但由于'if'条件,性能有点慢。 你能告诉我如何避免“如果”的条件吗? 有没有办法或努力避免'如果'。
提前致谢。
谢谢, Nilesh制作
答案 0 :(得分:2)
不,不是真的。如果你需要检查,你必须检查。您可以使用三元运算符替换if
,但几乎可以肯定地编译为相同的代码。
除非size()
方法特别复杂,否则我无法看到它拖累性能那么多。你可以 通过缓存Stack
类中的值来提高速度(我假设v
是某种向量)。
但是,如果它是一个向量,它完全能够自己作为一个堆栈,所以你可以让它自己引发异常,而不是强加你的例外。
您唯一缺少的是exch
方法,您可以这样做:
a = v.back(); v.pop_back();
b = v.back(); v.pop_back();
v.push_back(a);
v.push_back(b);
答案 1 :(得分:1)
你说检查条件相当于执行成本的很大一部分。问题是抛出异常还是if
本身是最高的成本。如果成本与实际抛出异常的情况相关联,那么您可能希望重构代码以使其无异常(返回代码似乎是一个很好的选择),因为异常是昂贵的。另外,请注意异常可能会产生很小的影响,即使它们没有被抛出 - 即。如果抛出异常,编译器必须跟踪在堆栈展开期间要销毁的对象集。编译器很聪明,所以期望成本很小,但不是零。
另一方面,如果不抛出异常,但成本确实与错误预测相关联,那么您可能希望返回到编译器供应商文档并查看如何提示它。许多编译器允许进行两阶段编译,在第一次编译之后,您可以运行测试和配置文件,并且可以将该分析信息交还给编译器,以便在知道应用程序的预期行为的情况下优化代码。 / p>
手动地,您还可以提示编译器关于检查的最期望结果是什么。特别是,一些编译器会假设if
的最可能结果是成功(输入if
,跳过else
),并且最可能的代码路径将进入if
。还有一些特殊的关键字可用于提示编译器,例如,在gcc中,您可以使用if (__builtin_expect( (condition), 0 ))
告诉编译器最可能的结果是condition
为假。
答案 2 :(得分:0)
您的if语句不是性能问题。在分析算法时,您可以将决策语句视为常量,或者换句话说,不会影响性能。这并不是说如果你有一些代码if (SomeExpensiveFn() == AnotherExpensiveFn())
,那么if部分(即结果的比较)不会忽略不计。
只有在不重新评估整个集合时才会这样。虽然1到n if语句不是性能问题。如果堆栈类导致N ^ 2 if if语句将被执行,那么您将看到性能下降。
此外,我认为这是作业,但如果不是std::stack
答案 3 :(得分:0)
如果您知道即将进行N pop()
而无需推送,则可以在客户端代码中对size()
进行一次检查,然后呼叫新的unsafe_pop()
成员不检查的功能。同样,当您的客户端代码可以更有效地保证足够的元素时,您可以拥有unsafe_exch()
。
但是,这里其他操作的费用会使if语句相形见绌...甚至擦除的指针算法(end() - 1)可能需要10倍的时间。如果你的性能需求是那么极端,你应该看得更深,还有替代算法,线程/并发等等。
答案 4 :(得分:0)
将if / throw更改为断言
答案 5 :(得分:0)
不,你不能删除if语句。
但是如果你以某种方式删除“抛出”,你可以稍微提高性能。抛出和捕获异常是一个缓慢的操作(如果您对以下内容感兴趣:http://www.codeproject.com/KB/cpp/exceptionhandler.aspx)。
所以,在Stack::exch()
中你可以放return
而不是throw..
。如果您想知道交换是否成功完成,您可以创建函数bool
并检查true
或false
。
但是你无法为弹出操作做任何事情。
此外,您可以更改v.size() < 0
(顺便说一下,此必须为v.size() <**=**0
,或者您可以尝试从空堆栈中pop
到if( ! v.empty() )
。
修改强>: 你可以这样编写这些函数:
int Stack::pop()
{
if ( v.empty() )
{
throw( "Error : Stack Underflow" );
}
int tos = v.back();
stack.erase( v.end() - 1 );
return tos;
}
bool Stack::exch() // Exchange top 2 element
{
if( v.size() < 2 )
{
return false;
}
std::vector< int >::size_type n = v.size();
int nTmp = v[ n - 1 ];
v[ n - 1 ] = v [ n - 2 ];
v[ n - 2 ] = nTmp;
return true;
}
答案 6 :(得分:0)
STL容器与您自己的代码的混合使我想知道您为什么不使用std::stack
?
坚持一个选择。
例如,代码中的弹出操作可以简单如下:
int Stack::pop()
{
if (size == 0)
throw("Error : Stack Underflow");
int tos = v[size-1];
--size;
return tos;
}
和
void Stack::exch() // Exchange top 2 element
{
if (size < 2)
throw("Error : Stack Underflow");
std::swap(v[size-1], v[size-2]);
}