前言
很长一段时间以来,宏定义一直被我视为效率极高的一种代码编写方式。
例如将求最值这类代码比较简单的函数改写为宏定义,可以省去传参的时间开销,极大地提高效率。因此宏定义屡试不爽。
然而直到昨天,在一道线段树的小题中,我意外发现了宏定义效率低于函数定义的情况。
代码
#include<cstdio>
#include<algorithm>
//#define max(a,b) (((a) < (b)) ? (b) : (a))
using namespace std;
const int N = 4 * 2 * 1e5 + 10;
int m,p;
struct Node{
int l,r;
int v;
}Tri[N];
void pushup(int u){
Tri[u].v = max(Tri[u<<1].v,Tri[u<<1|1].v);
}
void build(int u,int l,int r){
Tri[u].l = l,Tri[u].r = r;
if(l == r) return;
int m = l + r >> 1;
build(u << 1,l,m);build(u << 1 | 1,m + 1,r);
}
int query(int u,int l,int r){
if(Tri[u].l >= l and Tri[u].r <= r) return Tri[u].v;
int m = Tri[u].l + Tri[u].r >> 1;
int res = 0;
if(m >= l) res = query(u << 1,l,r);
if(m < r) res = max(res,query(u << 1 | 1,l,r));
return res;
}
void modify(int u,int idx,int x){
if(Tri[u].l == Tri[u].r){
Tri[u].v = x;
return;
}
int m = Tri[u].l + Tri[u].r >> 1;
if(m >= idx) modify(u << 1,idx,x);
else modify(u << 1 | 1,idx,x);
pushup(u);
}
int main(){
scanf("%d%d",&m,&p);
int a = 0;
build(1,1,m + 1);
int idx = 1;
while(m--){
char c[2];int t;scanf("%s%d",c,&t);
if(*c == 'A') modify(1,idx++,((long long)t + a) % p);
else a = query(1,idx - t,idx - 1),printf("%d\n",a);
}
return 0;
}
宏定义低效率原因分析
可以看到,12行和25行都调用了max函数,当将函数该写为宏时,不难看出,地25行的效率会大打折扣。
原因是max的第二个参数为query函数,但max为宏时,只需要计算一遍query函数得到返回值,再将返回值传递给max函数。
但当将max改写成宏之后,在单次执行时,可能会多调用一次query函数,而query的时间复杂度为
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n),在使用宏定义之后,反而增加了代码线性的复杂度。在数据规模较大时,最终会导致超时。
结论
并不是在任何时候使用宏定义的效率都会是最高的。
宏定义只在没有增加代码运算内容的前提下,能够在常数时间内提高效率。
原创不易,感谢支持。