Welcome to Liukejie's|

liukejie

园龄:1年8个月粉丝:5关注:11

比较实用的语法糖

《从 C++98 到 C++20,寻觅甜甜的语法糖们》

这篇文章对《从 C++98 到 C++20,寻觅甜甜的语法糖们》稍有改动

  • find(bg,ed,val)

    • 返回指向第一个等于 val 的元素的指针。

    • 时间复杂度 O(n)

    • 后文所有序列操作的函数,都以 n 代指 edbg

  • fill(bg,ed,val)

    • bged 之间的所有元素赋值为 val

    • 复杂度为 O(n),常数略大于 memset

    • val = 0x3f 时常数与 memset 相同。(存疑)

    • 常用于弥补 memset 无法赋值的问题,如赋值一个数组为 1

  • max_element/min_element(bg,ed)

    • 返回指向 bged 中最大/最小的元素的指针。

    • 时间复杂度 O(n)

    • 第三个参数可传入比较函数。

    • 求数组最大值就可以直接写:*max_element(a+1,a+n+1)

  • nth_element(bg,md,ed):

    • bged 中的内容重新分配顺序, md 的元素在 bgmd md 的元素都在 mded

    • 时间复杂度 O(n),需要 O(n) 的额外空间。

    • 第四个参数为比较函数,若不传则默认 less<>()

    • 常用于线性求序列中的第 k 大,常用于实现替罪羊树。

  • stable_sort(bg,ed)

    • bged 进行 稳定 排序。

    • 时间复杂度 O(nlogn),要 O(n) 的额外空间。

    • 当空间不足时使用 O(nlog2n) 的双调排序。

  • next_permutation(bg,ed)

    • bged 更改为下一个排列,并返回 1

    • bged 已经是最后一个排列,那么返回 0

    • 下一个排列的定义为字典序严格大于当前排列的下一个排列。

    • 时间复杂度 O(n)

    • 事实上 bged 不一定要是排列,可以存在相同元素。

    • 常用于枚举全排列:

    do{
    	// ...
    }while(next_permutation(p,p+n));
    
    • prev_permutation(bg,ed) 可以求出上一个排列。
  • merge(bg1,ed1,bg2,ed2,bg3)

    • bg1ed1bg2ed2 是两个有序序列,对其进行归并并存入 bg3

    • 不能够原地归并,若要原地归并请使用 inplace_merge

    • 时间复杂度 O(ed1bg1+ed2bg2)

    • 可以传入第六参数作为比较函数。

  • inplace_merge(bg,md,ed)

    • bgmdmded 归并排序,并存入 bg

    • 时间复杂度 O(n),需要 O(n) 的额外空间。

    • 当空间不足时使用 O(nlogn) 的原地排序。

    • 常数较小,可能比手写的还快。

    • 可以传入第四个参数作为比较函数。

    • 常用于 CDQ 分治等分治算法,非常好用。

  • count(bg,ed,val)

    • 返回 bged 中等于 val 的元素的个数。

    时间复杂度 O(n)

  • count_if(bg,ed,func)

    • 返回 bged 中使得函数 func 返回值为 \true 的元素的个数。

    • 时间复杂度 O(n×f)ffunc 的复杂度。

    • 常用的 func 有:islower/isupper/isdigit 等。

  • replace(bg,ed,val1,val2)

    • bged 中所有等于 val1 的元素替换为 val2

    • 时间复杂度 O(n)

  • for_each(bg,ed,func)

    • bged 中所有元素执行函数 func

    • 时间复杂度 O(n×f)

    • 其实没啥用,就是能压行。

  • accumulate(bg,ed,val)

    • bged 中的所有所有元素与初始值 val 相加,返回这个和。

    • 时间复杂度 O(n)

    • 可以传入第四个参数作为加法。

    • 可以用于求序列和,但注意,该函数返回值与 val 类型一致,意味着你要注意 long long 的问题:

    accumulate(bg,ed,0);//返回值是 int,可能溢出
    accumulate(bg,ed,0ll);//返回值是 long long
    
  • fabs(x)

    • 返回 x

    • 注意,对浮点运算请都使用 fabs 而不是 abs,因为有可能你调用的是 abs(int)

  • ceil(x)

    • 返回 x

    • 其返回值依旧是浮点类型,输出时注意格式。

  • floor(x)

    • 返回 x

    • 其返回值依旧是浮点类型,输出时注意格式。

  • shuffle(bg,ed,gen)

    • 打乱 bged 的顺序,gen 是一个随机数生成器(mt19937)。

    • 时间复杂度 O(n)

    • C++11 之后请尽量使用 shuffle 而不是 random_shuffle

  • is_sorted(bg,ed)

    • 判断 bged 是否升序排序。

    • 时间复杂度 O(n)

  • minmax(a,b)

    • 返回一个 pair<>,其 firstmin(a,b)secondmax(a,b)

    • 时间复杂度 O(1)

    • 常用于无向图存边的去重问题。

  • exp2(x)

    • 返回 2x
  • log2(x)

    • 返回 log2(x)
  • hypot(x,y)

    • 返回 x2+y2

    • 常用于求两点之间的距离,非常方便。

  • hypot(x,y,z)

    • 返回 x2+y2+z2

    • 复杂度 O(1)。

    • 常用来求三维中两点距离。

  • mt19937

    • 一个类型,作为随机数生成器。

    • 其构造函数应传入一个数字作为随机种子,使用时用法和 rand 相同。

    • 生成 unsigned int 范围内的随机数。

    mt19937 gen(123456); //123456 为随机种子
    int x = gen()%10000; //x will in [0,10000]
    uint32_t y = gen(); //normally y will in [0,2^32]
    
    • 随机种子通常为时间相关,下面的非常常用,建议背过
    mt19937 gen(chrono::system_clock::now().time_since_epoch().count());//chrono 在头文件 <chrono> 中
    
  • uniform_int_distribution(L,R)

    • 随机数发生器,每次调用时传入一个 mt19937,返回一个 LR 之间的整数,类型为 T,若 T 为空则默认为 int
  • uniform_real_distribution(L,R)

    • 随机数发生器,每次调用时传入一个 mt19937,返回一个 LR 之间的实数,类型为 T,若 T 为空则默认为 double
  • gcd(x,y) 或 lcm(x,y)

    • 返回 gcd(|x|,|y|)lcm(|x|,|y|) 的值。

    • 复杂度对数级别的。

    • 保证了返回值的符号是正。

    • lcm 的实现是先除后乘。

  • popcount(x)

    • 返回无符号整形 x 在二进制下 1 的个数。

    • 时间复杂度有说 O(loglogx) 的,也有说 O(1) 的,一定比手写的快。

    • 使用 __builtin_popcount 实现,但会检查传入的参数是否为无符号整形。

countl_zero(x);//从最高位起连续的 0 的数量
countr_zero(x);//从最低位起连续的 0 的数量
countl_one(x);//从最高位起连续的 1 的数量
countr_one(x);//从最低位起连续的 1 的数量
  • bit_width(x)

    • x=0 时返回 0,否则返回 1+log2(x)

    • 即二进制下 x 的位数。

    • 复杂度 O(1)

  • bit_floor(x)/bit_ceil(x)

    • 返回不超过 x 的最大的 2 的整次幂 / 不小于 x 的最小的 2 的整次幂。

    • 复杂度 O(1)

  • has_single_bit(x)

    • 返回 x 是否为 2 的整次幂,相当于 popcount(x)==1

    • 复杂度 O(1)

  • numbers 库

头文件 <numbers>,命名空间 std::numbers 中提供了大量的数学常数:

代码表示 数学表示
e_v e
log2e_v log2e
pi_v π
log10e_v log10e
inv_pi_v 1π
inv_sqrtpi_v 1π
ln2_v ln2
ln10_v ln10
sqrt2_v 2
sqrt3_v 3
inv_sqrt3_v 13
egamma_v 欧拉-马斯克若尼常数 γ
phi_v 黄金比 ϕ=5+12(注意这里是加号!!!)
  • 这些都是类模板,调用时请填入类型:
int main(){
  std::cout<<std::fixed<<std::setprecision(9)<<std::numbers::pi_v<double><<'\n';
}

去掉末尾的 _v 后直接就是一个常量:

cout<<numbers::e<<'\n';
posted @   liukejie  阅读(101)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起