比较实用的语法糖

文章详细介绍了C++从98标准到20标准中的一些重要语法糖,包括find、fill、max_element、min_element、nth_element、stable_sort等函数的使用,以及时间复杂度分析。同时,提到了随机数生成器mt19937和一些数学常数的内置支持。内容侧重于提高代码效率和编程便利性。
摘要由CSDN通过智能技术生成

# [《从 C++98 到 C++20,寻觅甜甜的语法糖们》](https://www.luogu.com.cn/blog/AccRobin/grammar-candies#)

# 这篇文章对《从 C++98 到 C++20,寻觅甜甜的语法糖们》稍有改动
- find(bg,ed,val)

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

    - 时间复杂度 $O(n)$。

    - **后文所有序列操作的函数,都以 $n$ 代指 $ed−bg$。**

- fill(bg,ed,val)

    - 将 $bg \sim ed$ 之间的所有元素赋值为 $val$。

    - 复杂度为 $O(n)$,常数略大于 `memset`。

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

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

- max_element/min_element(bg,ed)

    - 返回指向 $bg \sim ed$ 中最大/最小的元素的指针。

    - 时间复杂度 $O(n)$。

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

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

- nth_element(bg,md,ed):

    - 将 $bg \sim ed$ 中的内容重新分配顺序,$\le$ md 的元素在 $bg \sim md$,$\ge$ md 的元素都在 $md \sim ed$。
    
    - 时间复杂度 $O(n)$,需要 $O(n)$ 的额外空间。
    
    - 第四个参数为比较函数,若不传则默认 `less<>()`。
    
    - 常用于线性求序列中的第 $k$ 大,常用于实现替罪羊树。

- stable_sort(bg,ed)

    - 对 $bg \sim ed$ 进行 稳定 排序。

    - 时间复杂度 $O(n log ⁡n)$,要 $O(n)$ 的额外空间。

    - 当空间不足时使用 $O(n log⁡_2 n)$ 的双调排序。

- next_permutation(bg,ed)

    - 将 $bg \sim ed$ 更改为下一个排列,并返回 $1$。

    - 若 $bg \sim ed$ 已经是最后一个排列,那么返回 $0$。

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

    - 时间复杂度 $O(n)$。

    - 事实上 $bg \sim ed$ 不一定要是排列,可以存在相同元素。

    - 常用于枚举全排列:
    ```cpp
    do{
         // ...
    }while(next_permutation(p,p+n));
    ```
    - `prev_permutation(bg,ed)` 可以求出上一个排列。

- merge(bg1,ed1,bg2,ed2,bg3)

    - $bg1 \sim ed1$ 和 $bg2 \sim ed2$ 是两个有序序列,对其进行归并并存入 `bg3`。

    - 不能够原地归并,若要原地归并请使用 `inplace_merge`。

    - 时间复杂度 $O(ed1−bg1+ed2−bg2)$。

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

- inplace_merge(bg,md,ed)

    - 将 $bg \sim md$ 和 $md \sim ed$ 归并排序,并存入 `bg`。

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

    - 当空间不足时使用 $O(n log⁡ n)$ 的原地排序。

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

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

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

- count(bg,ed,val)

    - 返回 $bg \sim ed$ 中等于 $val$ 的元素的个数。
    
    时间复杂度 $O(n)$。
    
- count_if(bg,ed,func)

    - 返回 $bg \sim ed$ 中使得函数 `func` 返回值为 $\true$ 的元素的个数。
    
    - 时间复杂度 $O(n \times f)$,$f$ 为 `func` 的复杂度。
    
    - 常用的 `func` 有:`islower/isupper/isdigit` 等。
    
-  replace(bg,ed,val1,val2)

    - 将 $bg \sim ed$ 中所有等于 $val1$ 的元素替换为 $val2$。
    
    - 时间复杂度 $O(n)$。
    
- for_each(bg,ed,func)

    - 对 $bg \sim ed$ 中所有元素执行函数 `func`。
    
    - 时间复杂度 $O(n \times f)$。
    
    - 其实没啥用,就是能压行。
    
- accumulate(bg,ed,val)

    - 将 $bg \sim ed$ 中的所有所有元素与初始值 $val$ 相加,返回这个和。

    - 时间复杂度 $O(n)$。

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

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

    ```cpp
    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)

    - 打乱 $bg \sim ed$ 的顺序,`gen` 是一个随机数生成器(mt19937)。
    
    - 时间复杂度 $O(n)$。
    
    - C++11 之后请尽量使用 `shuffle` 而不是 `random_shuffle`。
    
- is_sorted(bg,ed)

    - 判断 $bg \sim ed$ 是否升序排序。
    
    - 时间复杂度 $O(n)$。
    
- minmax(a,b)

    - 返回一个 `pair<>`,其 `first` 为 $\min⁡(a,b)$,`second` 为 $\max⁡(a,b)$。
    
    - 时间复杂度 $O(1)$。
    
    - 常用于无向图存边的去重问题。

- exp2(x)

    - 返回 $2^x$。

- log2(x)

    - 返回 $log_2(x)$

- hypot(x,y)

    - 返回 $\sqrt {x^2 + y^2}$
    
    - 常用于求两点之间的距离,非常方便。
- hypot(x,y,z)

    - 返回 $\sqrt {x^2 + y^2 + z^2}$
    
    - 复杂度 O(1)。
    
    - 常用来求三维中两点距离。

- mt19937

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

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

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

    ```cpp
    mt19937 gen(123456); //123456 为随机种子
      int x = gen()%10000; //x will in [0,10000]
      uint32_t y = gen(); //normally y will in [0,2^32]
    ```
    - 随机种子通常为时间相关,下面的非常常用,建议背过

    ```cpp
    mt19937 gen(chrono::system_clock::now().time_since_epoch().count());//chrono 在头文件 <chrono> 中
      ```
 
- uniform_int_distribution<T>(L,R)

    - 随机数发生器,每次调用时传入一个 `mt19937`,返回一个 $L \sim R$ 之间的整数,类型为 $T$,若 $T$ 为空则默认为 `int`。
 
- uniform_real_distribution<T>(L,R)

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

    - 返回 $\gcd(|x|,|y|)$  或 $\operatorname {lcm}(|x|,|y|)$ 的值。

    - 复杂度对数级别的。
 
    - 保证了返回值的符号是正。
 
    - $\operatorname {lcm}$ 的实现是先除后乘。
 
- popcount(x)

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

    - 时间复杂度有说 $O( \log⁡⁡ \log x)$ 的,也有说 $O(1)$ 的,一定比手写的快。

    - 使用 `__builtin_popcount` 实现,但会检查传入的参数是否为无符号整形。
-
 
  ```cpp
  countl_zero(x);//从最高位起连续的 0 的数量
  countr_zero(x);//从最低位起连续的 0 的数量
  countl_one(x);//从最高位起连续的 1 的数量
  countr_one(x);//从最低位起连续的 1 的数量
  ```


- bit_width(x)

    - 当 $x = 0$ 时返回 $0$,否则返回 $1+⌊log⁡2(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 | $log_{2}e$ |
| pi_v | $\pi$ |
| log10e_v | $log_{10}e$ |
| inv_pi_v | $\frac{1}{\pi}$ |
| inv_sqrtpi_v | $\frac{1}{\sqrt{\pi}}$ |
| ln2_v | $\operatorname{ln}2$ |
| ln10_v | $\operatorname{ln}10$ |
| sqrt2_v | $\sqrt{2}$ |
| sqrt3_v | $\sqrt{3}$ |
| inv_sqrt3_v | $\frac{1}{\sqrt{3}}$ |
| egamma_v | 欧拉-马斯克若尼常数 $γ$ |
| phi_v | 黄金比 $ϕ= \frac{\sqrt5+1}{2}$(注意这里是加号!!!) |
  - 这些都是类模板,调用时请填入类型:
  ```cpp
  int main(){
    std::cout<<std::fixed<<std::setprecision(9)<<std::numbers::pi_v<double><<'\n';
  }
  ```
去掉末尾的 `_v` 后直接就是一个常量:
  ```cpp
  cout<<numbers::e<<'\n';
  ```

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

m0_62564583

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

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

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

打赏作者

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

抵扣说明:

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

余额充值