C++高性能并行编程与优化 - 课件 - 17 由浅入深学习 map 容器categories[key].push_back(str); } • 则 categories 最后为: • {‘h’: {“happy”, “hello”}, ‘w’: {“world”}}; 第二章:判断与删除 不鞋习的小彭友 就会进到这儿 ! 不鞋习的小彭友 就会进到这儿 ! 找不到时,自动采用默认值 • 要求:当 m 中有 “ key” 时返回 key 对应的值,否则返回指定的默认值 “ default” 覆盖旧值 创建并写入值 m.at(key) = val 覆盖旧值 抛出 out_of_range 异常 判断 if (m.count(key)) 返回 1 返回 0 删除 m.erase(key) 删除这个值 默默放弃 小彭老师四定律: 读取,要用 at 。 写入,要用 [] 。 判断存在,用 count 。 删除,用 erase 。 这四个已经够用了。 map 常用函数不同情况下的行为分析 m.insert_or_assign(key, val) 覆盖旧值 创建并写入值(更高效, C++17 新 增) m.at(key) = val 覆盖旧值 抛出 out_of_range 异常 判断 if (m.count(key)) 返回 1 返回 0 删除 m.erase(key) 删除这个值 默默放弃 对学有余力的同学,再扩充为小彭老师六定律: 安全的读取,要用 val = m.at(key)0 码力 | 90 页 | 8.76 MB | 1 年前3
Hello 算法 1.0.0b1 C++版需要会推算即可,数学意义可以慢慢领悟。 2.2.4. 推算方法 推算出 ?(?) 后,我们就得到时间复杂度 ?(?(?)) 。那么,如何来确定渐近上界 ?(?) 呢?总体分为两步,首 先「统计操作数量」,然后「判断渐近上界」。 1) 统计操作数量 对着代码,从上到下一行一行地计数即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作 数量 ?(?) 中的各种系数、常数项都可以被 i++) { for (int j = 0; j < n + 1; j++) { cout << 0 << endl; } } } 2. 复杂度分析 hello‑algo.com 18 2) 判断渐近上界 时间复杂度由多项式 ?(?) 中最高阶的项来决定。这是因为在 ? 趋于无穷大时,最高阶的项将处于主导作用, 其它项的影响都可以被忽略。 以下表格给出了一些例子,其中有一些夸张的值,是想要向大家强调 「暴力枚举」和「辅助哈希表」分别对应 空间最优 和 时间最优 的两种解法。本着时间比空间更宝贵的原则,后 者是本题的最佳解法。 方法一:暴力枚举 考虑直接遍历所有所有可能性。通过开启一个两层循环,判断两个整数的和是否为 target ,若是则返回它俩 的索引(即下标)即可。 // === File: leetcode_two_sum.cpp === /* 方法一:暴力枚举 */ vector0 码力 | 187 页 | 14.71 MB | 1 年前3
Hello 算法 1.0.0b4 C++版和 C 的时间复杂度相同,但实际运行时间差别很大。同 样,尽管算法 B 的时间复杂度比 C 高,但在输入数据大小 ? 较小时,算法 B 明显优于算法 C 。在这些情况下, 我们很难仅凭时间复杂度判断算法效率高低。当然,尽管存在上述问题,复杂度分析仍然是评判算法效率最 有效且常用的方法。 2.2.3. 函数渐近上界 设算法的计算操作数量是一个关于输入数据大小 ? 的函数,记为 ?(?) ,则以下算法的操作数量为 复杂度 hello‑algo.com 18 根据定义,确定 ?(?) 之后,我们便可得到时间复杂度 ?(?(?)) 。那么如何确定渐近上界 ?(?) 呢?总体分 为两步:首先统计操作数量,然后判断渐近上界。 第一步:统计操作数量 针对代码,逐行从上到下计算即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作数量 ?(?) 中的各种系数、常数项都可以被忽略。根据此原则,可以总结出以下计数简化技巧: (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { cout << 0 << endl; } } } 第二步:判断渐近上界 时间复杂度由多项式 ?(?) 中最高阶的项来决定。这是因为在 ? 趋于无穷大时,最高阶的项将发挥主导作用, 其他项的影响都可以被忽略。 以下表格展示了一些例子,其中一些夸张的值是为了强调“系数无法撼动阶数”这一结论。当0 码力 | 343 页 | 27.39 MB | 1 年前3
Hello 算法 1.1.0 C++ 版和 C 的时间复杂度相同,但实际运行时间差别很 大。同样,尽管算法 B 的时间复杂度比 C 高,但在输入数据大小 ? 较小时,算法 B 明显优于算法 C 。在 这些情况下,我们很难仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分析仍 然是评判算法效率最有效且常用的方法。 2.3.2 函数渐近上界 给定一个输入大小为 ? 的函数: void algorithm(int n) 不断的 实践中,就可以逐渐领悟其数学意义。 根据定义,确定 ?(?) 之后,我们便可得到时间复杂度 ?(?(?)) 。那么如何确定渐近上界 ?(?) 呢?总体分 为两步:首先统计操作数量,然后判断渐近上界。 1. 第一步:统计操作数量 针对代码,逐行从上到下计算即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作数量 ?(?) 中的各种系数、常数项都可以忽略。 。 ?(?) = 2?(? + 1) + (5? + 1) + 2 完整统计 (‑.‑|||) = 2?2 + 7? + 3 ?(?) = ?2 + ? 偷懒统计 (o.O) 2. 第二步:判断渐近上界 时间复杂度由 ?(?) 中最高阶的项来决定。这是因为在 ? 趋于无穷大时,最高阶的项将发挥主导作用,其他 项的影响都可以忽略。 表 2‑2 展示了一些例子,其中一些夸张的值是为了强调“系数无法撼动阶数”这一结论。当0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.0.0 C++版和 C 的时间复杂度相同,但实际运行时间差别很 大。同样,尽管算法 B 的时间复杂度比 C 高,但在输入数据大小 ? 较小时,算法 B 明显优于算法 C 。在 这些情况下,我们很难仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分析仍 然是评判算法效率最有效且常用的方法。 2.3.2 函数渐近上界 给定一个输入大小为 ? 的函数: void algorithm(int n) 不断的 实践中,就可以逐渐领悟其数学意义。 根据定义,确定 ?(?) 之后,我们便可得到时间复杂度 ?(?(?)) 。那么如何确定渐近上界 ?(?) 呢?总体分 为两步:首先统计操作数量,然后判断渐近上界。 1. 第一步:统计操作数量 针对代码,逐行从上到下计算即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作数量 ?(?) 中的各种系数、常数项都可以忽略。 。 ?(?) = 2?(? + 1) + (5? + 1) + 2 完整统计 (‑.‑|||) = 2?2 + 7? + 3 ?(?) = ?2 + ? 偷懒统计 (o.O) 2. 第二步:判断渐近上界 时间复杂度由 ?(?) 中最高阶的项来决定。这是因为在 ? 趋于无穷大时,最高阶的项将发挥主导作用,其他 项的影响都可以忽略。 表 2‑2 展示了一些例子,其中一些夸张的值是为了强调“系数无法撼动阶数”这一结论。当0 码力 | 378 页 | 17.59 MB | 1 年前3
Hello 算法 1.0.0b5 C++版和 C 的时间复杂度相同,但实际运行时间差别很 大。同样,尽管算法 B 的时间复杂度比 C 高,但在输入数据大小 ? 较小时,算法 B 明显优于算法 C 。在 这些情况下,我们很难仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分析仍 然是评判算法效率最有效且常用的方法。 2.3.2 函数渐近上界 给定一个输入大小为 ? 的函数: 第 2 章 复杂度分析 hello‑algo 要掌握 推算方法,数学意义就可以逐渐领悟。 根据定义,确定 ?(?) 之后,我们便可得到时间复杂度 ?(?(?)) 。那么如何确定渐近上界 ?(?) 呢?总体分 为两步:首先统计操作数量,然后判断渐近上界。 1. 第一步:统计操作数量 针对代码,逐行从上到下计算即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作数量 ?(?) 中的各种系数、常数项都可以被忽略 。 ?(?) = 2?(? + 1) + (5? + 1) + 2 完整统计 (‑.‑|||) = 2?2 + 7? + 3 ?(?) = ?2 + ? 偷懒统计 (o.O) 2. 第二步:判断渐近上界 时间复杂度由多项式 ?(?) 中最高阶的项来决定。这是因为在 ? 趋于无穷大时,最高阶的项将发挥主导作用, 其他项的影响都可以被忽略。 第 2 章 复杂度分析 hello‑algo.com0 码力 | 377 页 | 30.69 MB | 1 年前3
Hello 算法 1.2.0 简体中文 C++ 版如果把具体的工作技能比作是武功的“招式”的话,那么基础科目应该更像是“内功”。 我认为学算法(以及其他基础科目)的意义不是在于在工作中从零实现它,而是基于学到的知识,在解决问 题时能够作出专业的反应和判断,从而提升工作的整体质量。举一个简单例子,每种编程语言都内置了排序 函数: ‧ 如果我们没有学过数据结构与算法,那么给定任何数据,我们可能都塞给这个排序函数去做了。运行顺 畅、性能不错,看上去并没有什么问题。 C 的时间复杂度相同,但实际运行时间差别很 大。同样,尽管算法 B 的时间复杂度比 C 高,但在输入数据大小 ? 较小时,算法 B 明显优于算法 C 。对 于此类情况,我们时常难以仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分 析仍然是评判算法效率最有效且常用的方法。 2.3.2 函数渐近上界 给定一个输入大小为 ? 的函数: void algorithm(int n) 不断的 实践中,就可以逐渐领悟其数学意义。 根据定义,确定 ?(?) 之后,我们便可得到时间复杂度 ?(?(?)) 。那么如何确定渐近上界 ?(?) 呢?总体分 为两步:首先统计操作数量,然后判断渐近上界。 1. 第一步:统计操作数量 针对代码,逐行从上到下计算即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作数量 ?(?) 中的各种系数、常数项都可以忽略。0 码力 | 379 页 | 18.48 MB | 10 月前3
Hello 算法 1.0.0b2 C++版需要会推算即可,数学意义可以慢慢领悟。 2.2.4. 推算方法 推算出 ?(?) 后,我们就得到时间复杂度 ?(?(?)) 。那么,如何来确定渐近上界 ?(?) 呢?总体分为两步,首 先「统计操作数量」,然后「判断渐近上界」。 1) 统计操作数量 对着代码,从上到下一行一行地计数即可。然而,由于上述 ? ⋅ ?(?) 中的常数项 ? 可以取任意大小,因此操作 数量 ?(?) 中的各种系数、常数项都可以被 i++) { for (int j = 0; j < n + 1; j++) { cout << 0 << endl; } } } 2. 复杂度分析 hello‑algo.com 18 2) 判断渐近上界 时间复杂度由多项式 ?(?) 中最高阶的项来决定。这是因为在 ? 趋于无穷大时,最高阶的项将处于主导作用, 其它项的影响都可以被忽略。 以下表格给出了一些例子,其中有一些夸张的值,是想要向大家强调 「暴力枚举」和「辅助哈希表」分别对应 空间最优 和 时间最优 的两种解法。本着时间比空间更宝贵的原则,后 者是本题的最佳解法。 方法一:暴力枚举 考虑直接遍历所有所有可能性。通过开启一个两层循环,判断两个整数的和是否为 target ,若是则返回它俩 的索引(即下标)即可。 // === File: leetcode_two_sum.cpp === /* 方法一:暴力枚举 */ vector0 码力 | 197 页 | 15.72 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 11 现代 CMake 进阶指南Release ,指 定的时候保持用户指定的值不变呢。 就是说 CMake 默认情况下 CMAKE_BUILD_TYPE 是一个空字符串。 因此这里通过 if (NOT CMAKE_BUILD_TYPE) 判断是否为空,如果空 则自动设为 Release 模式。 大多数 CMakeLists.txt 的开头都会有这样三行,为的是让默认的构建类 型为发布模式(高度优化)而不是默认的调试模式(不会优化)。 我们稍后会详细捋一遍类似于 时定义 WITH_TBB 宏,稍后 .cpp 里就可以根据这个判断。 如果找不到 TBB 可以 fallback 到保守的实现。 这样在 .cpp 里可以判断 WITH_TBB 宏,找不到 TBB 时退化到串行 for 循环 也可以用 TARGET 判断是否存在 TBB::tbb 这个伪对象,实现同样效果 也可以复合 if 的各种判断语句,例如 NOT TARGET TBB::tbb AND TARGET s.7.html#genex:PLATFORM_ID 判断当前用的是哪一款 C++ 编译器 https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html#variable:CMAKE_%3CLANG%3E_COMPILER_ID 也可以用生成器表达式判断编译器 https://cmake.org/cmake0 码力 | 166 页 | 6.54 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 性能优化之无分支编程 Branchless Programming5 10 20 条件跳转指令 • 让不占用相同资源的任务同时进行,这也是 CPU 流水线的初衷。但理想是美好的,现实 是骨感的,对于程序来说,指令不只是一个 个简单的任务,有时候我们需要做判断,来 决定要执行的具体任务,这就是分支,在汇 编语言中体现为条件跳转指令。 • 例如我们这里给任务清单加一个,如果烧开 水时被烫伤,则直接去医院的特殊任务。 • 特点:一旦触发去医院这个支线,则后面的 (无条件)跳转到结束 去医院 10 分钟 全身 结束 跳转指令对流水线效率的影响 • 然而跳转指令的存在使得流水线的并行变得很困难了。例如我们本来可以烧开水和刷牙同 时进行节省时间的,但是因为烧好开水以后还要判断“是否烫伤”才能决定接下来是正常刷牙 还是去医院。这意味着流水线不得不在跳转指令前后发生断层(俗称流水线里的气泡)。 不得不等待烧开水这个任务结束,才能确定接下来要执行哪个剧本:正常继续早餐,还是 说要前往医院。 很多同学通常都会用 switch 来处理这种 大量判断的情况。可能你误以为 switch 比一堆 if-else 更高效。但是实际上在编译 器看来是一样的,不管你 if-else 还是 switch ,他都会想方设法帮你优化成查表 法。 • 所以不用纠结性能,你觉得哪种写起来可 读性强,容易维护,你就怎么写。 无分支优化的方法:查表法 • 如果每个判断的值是连续的,这种情况一般 会建立一个表(数组)。0 码力 | 47 页 | 8.45 MB | 1 年前3
共 28 条
- 1
- 2
- 3













