--- title: "库函数专辑" created: 2025-11-28 tags: - 算法 --- # 库函数专辑 ## 四舍五入 ### round `round`函数用于四舍五入浮点数到最接近的整数。如果参数的小数部分是`.5`,则这个函数会将数值四舍五入到最近的偶数整数。这是为了遵守IEEE浮点数的标准,减少四舍五入操作的累积误差。 - **语法:** `double round(double x);` - **例子:** `round(2.3)` 返回 `2.0`, `round(3.5)` 返回 `4.0`, `round(4.5)` 返回 `4.0`。 ## 向下取整 ### floor `floor`函数将浮点数向下取整到最接近的整数,但不大于原数。无论原数的小数部分是多少,都会被丢弃,仅保留整数部分。 - **语法:** `double floor(double x);` - **例子:** `floor(2.3)` 返回 `2.0`, `floor(-3.8)` 返回 `-4.0`。 ## 向上取整 ### ceil `ceil`函数将浮点数向上取整到最近的整数,但不小于原数。这意味着它会舍弃原数的小数部分,并在有小数的情况下将整数部分加一。 - **语法:** `double ceil(double x);` - **例子:** `ceil(2.3)` 返回 `3.0`, `ceil(-3.8)` 返回 `-3.0`。 ## 幂运算 ### pow 用于计算一个数的指数幂。 **应用场景**:计算一个电子的电位能量,给定电荷量(Q)和电场强度(E)的情况下,电位能量(U)可以使用公式`U = Q * E * d`计算,其中d是电场中的位置深度,假设我们需要计算d的平方对结果的影响。 ```cpp #include #include using namespace std; int main() { double Q = 1.6e-19; // 电荷量,单位库仑 double E = 500; // 电场强度,单位牛顿/库仑 double d = 0.05; // 位置深度,单位米 double U = Q * E * pow(d, 2); // 计算d的平方对U的影响 cout << "Potential Energy: " << U << " Joules" << endl; return 0; } ``` ## 平方根 ### sqrt **应用场景**:计算直角三角形的斜边长度,给定两条直角边的长度。 ```cpp #include #include using namespace std; int main() { double a = 3.0, b = 4.0; double c = sqrt(pow(a, 2) + pow(b, 2)); // 根据勾股定理计算斜边长度 cout << "Hypotenuse: " << c << endl; return 0; } ``` ## 对数 ### log2 和 log10 ### 计算二进制表示所需的位数 `log2` 函数计算以2为底的对数,这在需要处理与二进制相关的问题时非常有用。比如,计算一个正整数在二进制表示中需要多少位。这对于算法竞赛中的位操作题目,比如求解一个数的二进制中1的数量,或者需要用位掩码表示某些状态时,非常实用。 ```cpp #include #include using namespace std; int main() { int n; cout << "Enter a positive integer: "; cin >> n; int bitsNeeded = log2(n) + 1; // 加1因为log2(n)计算的是索引,而位数从1开始计数 cout << "Bits needed for binary representation of " << n << ": " << bitsNeeded << endl; return 0; } ``` 这个例子假设`n`是一个正整数。`log2(n)`计算了`n`在二进制表示下的最高位的位置(从0开始计数),因此需要加1来得到总位数。 ### 计算十进制数中的位数 `log10` 函数计算以10为底的对数,它可以用来快速确定一个数在十进制表示中的位数。这在处理需要数位操作的算法问题时特别有用,比如数字反转、数位和计算等。 ```cpp #include #include using namespace std; int main() { int n; cout << "Enter a positive integer: "; cin >> n; int digits = log10(n) + 1; // 加1因为log10(n)计算的是最高位的索引 cout << "Digits in the decimal representation of " << n << ": " << digits << endl; return 0; } ``` 这个例子演示了如何快速计算出一个正整数在十进制表示中的位数。类似于`log2`的用法,这里`log10(n)`计算的是`n`的最高位的位置索引,在十进制中,这个位置索引加1就是该数的总位数。 ## 其他 ### modf - 分解浮点数 **应用场景**:如果要将一个浮点数的小时表示转换为小时和分钟(例如,将3.75小时转换为3小时45分钟),可以使用`modf`。 ```cpp #include #include using namespace std; int main() { double hours; cin >> hours; double intpart, fracpart; fracpart = modf(hours, &intpart); int minutes = round(fracpart * 60); cout << intpart << " hours and " << minutes << " minutes" << endl; return 0; } ``` ### fmod - 浮点数除法的余数 **应用场景**:计算一个飞轮每分钟转动7.5圈,经过98分钟后,它总共转了多少圈,并计算其相对于整圈的余数(即最后停留的位置)。 ```cpp #include #include using namespace std; int main() { double rotationsPerMinute = 7.5; double timeInMinutes = 98; double totalRotations = rotationsPerMinute * timeInMinutes; double remainder = fmod(totalRotations, 1); // 计算相对于整圈的余数 cout << "Remainder: " << remainder << " of a rotation" << endl; return 0; } ``` ## 输入 ### `getline` - **用法**:`getline(cin, stringVar);` - **目的**:读取一整行文本,直到遇到换行符`\n`。`getline`会丢弃换行符,但会读取并保留行中的其他所有字符,**包括空格**。 - **场景**:当你需要读取包含空格的一行文本或者确保一次读取直到行末尾时,`getline`是最佳选择。 - **注意**:在`getline`之前使用`cin`或`scanf`读取其他数据,并且期望紧接着用`getline`读取下一行时,需要注意消耗掉留在输入缓冲区中的换行符。 如:家族 ### `cin` - **用法**:`cin >> variable;` - **目的**:读取数据,使用空格、制表符或换行符作为分隔符。`cin`会自动忽略任何前导空白字符。 - **场景**:适用于读取分隔开的单个数据项,如整数、浮点数、字符串(不含空格)。 - **优点**:使用方便,支持连锁调用(如`cin >> a >> b;`)。 - **缺点**:不能读取含有空格的字符串。 ### `scanf` - **用法**:`scanf("%format_specifier", &variable);` - **目的**:根据指定的格式读取数据。`scanf`提供了格式化输入的能力,可以按照特定的格式读取数据。 - **场景**:当输入数据遵循固定格式,且需要精确控制输入格式时使用。它对于读取复杂格式化的输入非常有效。 - **优点**:读取速度快,可以精确地控制输入数据的格式。 - **缺点**:使用不当容易出错,如忽略返回值可能会导致未定义行为。对于字符串的处理不如`cin`和`getline`直观。 **常用格式控制** 整数 - `%d`:读取一个十进制整数。 - `%ld`和`%lld`:分别用于读取`long`和`long long`类型的十进制整数。 - `%u`:读取一个无符号十进制整数。 - `%x`或`%X`:读取一个十六进制整数。 - `%o`:读取一个八进制整数。 浮点数 - `%f`:读取一个浮点数(`float`或`double`)。 - `%lf`:读取一个`double`类型的浮点数。虽然`%f`在`printf`中用于`double`,但在`scanf`中`%f`是用于`float`的,`%lf`用于`double`。 字符和字符串 - `%c`:读取一个字符。 - `%s`:读取一个字符串,直到遇到空白字符(空格、制表符或换行符)为止。读取的字符串自动以空字符`\0`结尾。 其他 - `%p`:读取一个指针。 - `%%`:读取一个`%`字符。 读取多个值 `scanf`可以在一个调用中读取多个值,格式说明符之间的空格将被忽略,输入中的空格、制表符和换行符可以在任何格式说明符之间进行匹配。 示例 ```cpp int a, b; scanf("%d %d", &a, &b); char ch; scanf(" %c", &ch); // 注意前面的空格,用于跳过前面的空白字符 double d; scanf("%lf", &d); char str[100]; scanf("%s", str); // 不需要&,因为数组名本身就是地址 ``` 注意事项 - 当使用`%s`读取字符串时,确保目标数组足够大,以避免缓冲区溢出。 - 使用`%c`读取字符时,如果想要忽略前面的空白字符(包括空格、制表符和换行符),可以在`%c`之前加一个空格,如`scanf(" %c", &ch);`。 - 对于`scanf`来说,必须提供变量的地址作为参数(使用`&`运算符),除了字符串数组因为数组名已经是地址。 - 使用`scanf`时要特别注意返回值,它返回成功读取的项目数。这个返回值可以用来检测输入是否按照预期进行。 ### `getchar` - **用法**:`int c = getchar();` - **目的**:从标准输入读取下一个字符,并返回它。如果遇到文件结束符(EOF),则返回`EOF`。 - **场景**:适用于需要逐字符读取输入时,如处理输入流中的空格、换行符等特殊字符。 ### 总结 在算法竞赛中,选择哪种输入方法取决于具体任务的需求: - 如果你需要读取整行数据,特别是包含空格的字符串,使用`getline`。 - 对于分隔的数据项,特别是不包含空格的字符串或数字,`cin`是一个方便的选项。 - 当输入格式非常具体,或者在性能极其关键的情况下,`scanf`可能是最好的选择,尽管它需要更多的注意来避免错误。 - 读取单个字符,逐字符处理,使用`getchar`: ## 输出 ### `cout` - **用法**:`cout << value << ...;` - **目的**:输出数据到标准输出。`cout`是C++中的标准输出流对象。 - **场景**:适用于大多数输出需求,特别是当需要输出字符串、数字或是其他复合数据结构时。`cout`由于是类型安全的,因此在处理类似于字符串和数字混合输出时非常方便。 - **优点**: - 类型安全,自动类型推断。 - 支持连锁调用,易于使用。 - 可以与C++标准库中的其他流对象一起使用,如文件流。 - **缺点**: - 相比于`printf`,在处理格式化输出时可能不那么灵活。 - 在某些情况下,可能比`printf`慢,尤其是没有优化I/O性能时。 使用 `ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);`进行优化 ### `printf` - **用法**:`printf("format specifier", value1, value2, ...);` - **目的**:根据指定的格式输出数据。`printf`是C语言中的标准输出函数,但在C++中仍然可用。 - **场景**:当需要精确控制输出格式,比如指定浮点数的精度,或者输出的宽度时。 - **优点**: - 高度格式化的输出。 - 在某些情况下,性能优于`cout`。 - **缺点**: - 不是类型安全的,错误的格式说明符可能导致运行时错误 **常用格式控制** `printf`非常强大,支持多种格式控制符,可以精确地控制输出格式。 - `%d`:输出十进制整数。 - `%u`:输出无符号十进制整数。 - `%f`:输出浮点数,默认情况下保留小数点后六位。 - `%.2f`:输出浮点数,小数点后保留两位。 - `%s`:输出字符串。 - `%c`:输出单个字符。 - `%x`或`%X`:输出十六进制数,`x`产生小写字母,`X`产生大写字母。 - `%p`:输出指针地址。 - `%%`:输出`%`字符。 **高级用法** - **指定宽度**:`%5d`表示输出的整数至少占5个字符宽度,如果数字位数不够,前面补空格。 - **左对齐**:`%-5d`表示输出的整数左对齐,至少占5个字符宽度。 - **指定浮点数精度**:`%.3f`表示输出的浮点数保留三位小数。 - **动态宽度和精度**:`%*.*f`允许动态指定宽度和精度,这两个值由额外的参数提供。 例如: ```cpp printf("%5d\n", 123); // " 123" printf("%-5d\n", 123); // "123 " printf("%.3f\n", 3.1415926); // "3.142" ``` ### `puts`和`putchar` - `puts`: - **用法**:`puts(const char* s);` - **目的**:输出字符串`s`到标准输出,并自动在末尾添加换行符。 - **优点**:简单易用,自动添加换行符,适合快速输出一行字符串。 - **缺点**:只能输出字符串,不能格式化输出其他类型的数据。 - `putchar`: - **用法**:`putchar(int char);` - **目的**:输出单个字符到标准输出。 - **优点**:非常简单,用于输出单个字符。 - **缺点**:每次只能输出一个字符,不适用于复杂的输出需求。 ### 总结 根据需要输出的数据类型和格式化要求来决定。`cout`适合大部分场景且易于使用;`printf`在需要特定格式时更为强大;而`puts`和`putchar`适用于简单的输出需求,特别是当性能要求较高时。 ## 常用算法 ### unique 在C++中,`unique` 函数是一个非常有用的工具,它用于移除序列中的连续重复元素,通常与 `sort` 函数结合使用来移除所有重复元素。`unique` 函数是 `` 头文件的一部分。下面是如何使用 `unique` 函数的详细介绍: #### 基本用法 `unique` 函数通常接受两个迭代器作为参数,表示要处理的序列的开始和结束。它将连续的重复元素移至序列的末尾,并返回一个迭代器,指向去除重复元素后序列的新逻辑末尾。 ```cpp #include #include #include int main() { std::vector v = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; // 使用 unique 函数 auto it = std::unique(v.begin(), v.end()); // 移除重复之后,需要调用 erase 来缩减容器大小 v.erase(it, v.end()); for (int x : v) { std::cout << x << " "; } return 0; } ``` #### 和 `sort` 结合使用 如果要移除一个序列中所有的重复元素,首先需要对序列进行排序。`unique` 只能移除相邻的重复元素。 ```cpp #include #include #include int main() { std::vector v = {4, 2, 2, 3, 3, 1, 4, 4}; // 首先排序 std::sort(v.begin(), v.end()); // 然后使用 unique auto it = std::unique(v.begin(), v.end()); // 移除重复之后,需要调用 erase 来缩减容器大小 v.erase(it, v.end()); for (int x : v) { std::cout << x << " "; } return 0; } ``` #### 自定义比较函数 `unique` 也可以接受第三个参数,这是一个比较函数,用于定义什么构成重复。这允许在去重时使用自定义的比较逻辑。 ```cpp #include #include #include bool customCompare(int a, int b) { return a == b; } int main() { std::vector v = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; // 使用自定义比较函数 auto it = std::unique(v.begin(), v.end(), customCompare); // 移除重复之后,需要调用 erase 来缩减容器大小 v.erase(it, v.end()); for (int x : v) { std::cout << x << " "; } return 0; } ``` ### lower\_bound 在C++中,`lower_bound` 是一个非常有用的标准库函数,它用于在已排序的序列中找到第一个不小于(即大于或等于)给定值的元素的位置。这个函数定义在 头文件中,并可以与任何类型的迭代器一起使用,如数组、向量等。以下是 `lower_bound` 的基本用法和一些高级应用。 #### 基本用法 `lower_bound` 函数通常接受四个参数:序列的开始迭代器、结束迭代器、要查找的值和可选的比较函数。如果不提供比较函数,则使用元素的默认小于操作符进行比较。 下面是使用 `lower_bound` 的一个示例: ```cpp #include #include #include int main() { std::vector v = {1, 3, 5, 7, 9}; // 查找第一个不小于 6 的元素 auto it = std::lower_bound(v.begin(), v.end(), 6); if (it != v.end()) { std::cout << "The first element not less than 6 is: " << *it << std::endl; } else { std::cout << "No element not less than 6" << std::endl; } return 0; } ``` #### 与上界结合 `lower_bound` 可以与 `upper_bound` 结合使用,以找到一个特定范围,其中包括所有等于给定值的元素。`upper_bound` 查找第一个大于指定值的元素的迭代器。 ```cpp #include #include #include int main() { std::vector v = {1, 2, 2, 3, 3, 3, 4, 4}; // 查找值为 3 的范围 auto lb = std::lower_bound(v.begin(), v.end(), 3); auto ub = std::upper_bound(v.begin(), v.end(), 3); std::cout << "Elements equal to 3: "; for (auto it = lb; it != ub; ++it) { std::cout << *it << " "; } std::cout << std::endl; return 0; } ``` #### 使用自定义比较函数 如果你的数据结构较为复杂,或者你想根据某些自定义的规则进行元素比较,你可以向 `lower_bound` 传递一个比较函数。 ```cpp #include #include #include bool compare(int a, int b) { return a < b; } int main() { std::vector v = {1, 3, 5, 7, 9}; // 使用自定义比较函数查找第一个不小于 4 的元素 auto it = std::lower_bound(v.begin(), v.end(), 4, compare); if (it != v.end()) { std::cout << "The first element not less than 4 is: " << *it << std::endl; } else { std::cout << "No element not less than 4" << std::endl; } return 0; } ``` --- ⬅️ [[计算几何|计算几何]] 🏠 [[00-刷题理模型]] ➡️ [[10、星际探险|10、星际探险]]