辩证宏定义效率

19 篇文章 2 订阅
5 篇文章 0 订阅

前言

很长一段时间以来,宏定义一直被我视为效率极高的一种代码编写方式。
例如将求最值这类代码比较简单的函数改写为宏定义,可以省去传参的时间开销,极大地提高效率。因此宏定义屡试不爽。
然而直到昨天,在一道线段树的小题中,我意外发现了宏定义效率低于函数定义的情况。

代码

#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),在使用宏定义之后,反而增加了代码线性的复杂度。在数据规模较大时,最终会导致超时。

结论

并不是在任何时候使用宏定义的效率都会是最高的。
宏定义只在没有增加代码运算内容的前提下,能够在常数时间内提高效率。


原创不易,感谢支持。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wingaso

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值