Boost C++ 库

世界上最受推崇、设计最精良的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ Coding Standards

第 1 章 Boost.Icl - Boost C++ 函数库
Next

第 1 章 Boost.Icl

Joachim Faulhaber

根据 Boost 软件许可证版本 1.0 发布。(参见随附文件 LICENSE_1_0.txt 或在 https://boost.ac.cn/LICENSE_1_0.txt 复制)

目录

介绍
定义和基本示例
Icl 的类模板
区间合并样式
示例
概述
聚会
Interval
动态区间
静态区间
区间容器
重叠计数器
聚会身高平均值
聚会最高宾客
月份和周的时间网格
人力
用户组
Std copy
Std transform
自定义区间
项目
大型位集
概念
命名
方面
集合和映射
重叠时的可加性、可减性和聚合性
Map Traits
语义
排序和等价
集合
映射
收集器:集合的映射
量词:数字的映射
概念归纳
接口
类模板
所需概念
关联类型
函数概要
定制
区间
实现
迭代大小
复杂度
就地和中缀运算符
函数参考
重载表
分段精度
关键类型
构造、复制、析构
包含关系
相等和排序
大小
范围
选择
加法
减法
插入
删除
交集
对称差集
与迭代器相关
元素迭代
流式处理、转换
区间构造
附加区间排序
杂项区间函数
致谢
区间容器库参考
头文件 <boost/icl/closed_interval.hpp>
头文件 <boost/icl/continuous_interval.hpp>
头文件 <boost/icl/discrete_interval.hpp>
头文件 <boost/icl/dynamic_interval_traits.hpp>
头文件 <boost/icl/functors.hpp>
头文件 <boost/icl/gregorian.hpp>
头文件 <boost/icl/impl_config.hpp>
头文件 <boost/icl/interval.hpp>
头文件 <boost/icl/interval_base_map.hpp>
头文件 <boost/icl/interval_base_set.hpp>
头文件 <boost/icl/interval_bounds.hpp>
头文件 <boost/icl/interval_combining_style.hpp>
头文件 <boost/icl/interval_map.hpp>
头文件 <boost/icl/interval_set.hpp>
头文件 <boost/icl/interval_traits.hpp>
头文件 <boost/icl/iterator.hpp>
头文件 <boost/icl/left_open_interval.hpp>
头文件 <boost/icl/map.hpp>
头文件 <boost/icl/open_interval.hpp>
头文件 <boost/icl/ptime.hpp>
头文件 <boost/icl/rational.hpp>
头文件 <boost/icl/right_open_interval.hpp>
头文件 <boost/icl/separate_interval_set.hpp>
头文件 <boost/icl/split_interval_map.hpp>
头文件 <boost/icl/split_interval_set.hpp>
[Note] 注意

C++03 支持Boost.Icl 1.84 版本中已弃用,并将在 Boost.Icl 1.86 中移除。

区间在软件开发中几乎无处不在。然而,它们只需一对数字即可轻松编码到用户定义的类中,因此大多数时候它们只被 隐式 使用。区间的含义很简单。它们代表其下界和上界之间的所有元素,因此是一个集合。但与集合不同,区间通常不能合并成一个新的区间。如果您想将区间添加到仍然代表一个 集合 的区间集合中,您就会想到本库提供的 区间集合 (interval_sets)

ICL 的区间容器最初是在 Cortex Software GmbH 开发的,用于解决在医院信息系统背景下与日期和时间区间计算相关的问题。需要对具有相关值的时区(如 发票金额治疗方案集)进行统计、计费程序和治疗计划程序的处理。因此,ICL 源于这些工业用例。它提取了有助于解决从日期和时间问题域中提取通用问题的通用代码,并且在其他领域也可能受益。

区间容器最显著的优点之一是它们对集合和映射的表示非常紧凑。如果在一个给定的问题域中,元素通常以连续的块出现,那么处理 元素 的集合和映射可能会非常低效。除了紧凑的关联容器表示(可以大大降低空间和时间成本)之外,ICL 还提供了一个通用的聚合机制,允许在插入时区间重叠时以有意义的方式组合相关值。

有关简洁的介绍和概述,您可以查看 来自 BoostCon2009 的关于 ICL 的演示材料

区间容器库 (ICL) 提供了 区间 和两种区间容器:区间集合 (interval_sets)区间映射 (interval_maps)

  • Interval_set 是一个 集合,它实现为一个区间的集合。
  • Interval_map 是一个 映射,它实现为一个区间值对的映射。
两个方面

Interval_setsinterval_maps 在它们的接口中暴露了两个不同的方面:(1) 集合或映射的功能,这是更 抽象的方面。以及 (2) 区间容器的功能,这是更具体、更 与实现相关的方面。在实践中,这两个方面都有用,因此都得到了支持。

第一个方面,称为 基本 方面,更为重要。这意味着我们可以将 interval_setinterval_map 用作 元素的 集合或映射。它暴露了相同的功能。

interval_set<int> mySet;
mySet.insert(42);
bool has_answer = contains(mySet, 42);

第二个方面,称为 段状 方面,允许利用 interval_setsinterval_maps 的元素聚集在 区间 中,我们可以迭代遍历。

// Switch on my favorite telecasts using an interval_set
interval<seconds>::type news(make_seconds("20:00:00"), make_seconds("20:15:00"));
interval<seconds>::type talk_show(make_seconds("22:45:30"), make_seconds("23:30:50"));
interval_set<seconds> myTvProgram;
myTvProgram.add(news).add(talk_show);

// Iterating over elements (seconds) would be silly ...
for(interval_set<seconds>::iterator telecast = myTvProgram.begin();
    telecast != myTvProgram.end(); ++telecast)
    //...so this iterates over intervals
   TV.switch_on(*telecast);

当集合的元素以连续块出现时,使用 interval_setsinterval_maps 可能是有益的:区间。这显然在许多问题域中都适用,特别是在处理日期和时间相关的计算领域。

可加性和可减性

std::setsmaps 不同,interval_setsinterval_maps 实现 AddableSubtractable 概念。因此,interval_sets 定义了一个 operator +=,它自然地实现为 集合并集,以及一个 operator -=,它相应地实现为 集合差集。在 Icl 中,interval_maps 也是可加和可减的。将区间值对的添加或减法传播到 interval_map 的相关值中,在将区间值对插入 interval_map 时导致与已在 interval_map 中的区间值对发生冲突的情况下,这被证明是一个非常有益的概念。这种操作传播称为 重叠时聚合

重叠时聚合

这是一个关于一个小聚会的第一个激励性示例,它演示了 interval_maps 上的 重叠时聚合 原则。

在示例中,玛丽首先参加聚会。她在 [20:00,22:00) 的时间段内参加。哈里稍后到达。他在 [21:00,23:00) 的时间内逗留。

typedef std::set<string> guests;
interval_map<time, guests> party;
party += make_pair(interval<time>::right_open(time("20:00"), time("22:00")), guests("Mary"));
party += make_pair(interval<time>::right_open(time("21:00"), time("23:00")), guests("Harry"));
// party now contains
[20:00, 21:00)->{"Mary"}
[21:00, 22:00)->{"Harry","Mary"} //guest sets aggregated on overlap
[22:00, 23:00)->{"Harry"}

在区间重叠时,相应的姓名集被 累加。在 重叠点,区间被 分割。区间重叠时内容的累加是通过一个 operator += 完成的,该操作符必须为 interval_map 的相关值实现。在示例中,相关值是 guest sets。因此,guest set 必须将 operator += 实现为集合并集。

从示例可以看出,interval_map 既有 分解行为(在时间维度上),也有 累加行为(在相关值上)。

可加性和重叠时聚合是 interval_maps 上的有用功能,通过函数 addoperator += 实现。但您也可以使用 传统插入语义,其行为类似于 std::map::insert,并针对区间插入进行了泛化。

除了区间容器,我们还可以使用与区间容器 行为等效 的元素容器:在基本方面,它们具有完全相同的功能。STL 的 std::set 就是这样一种等效的集合实现。由于 icl 区间映射的聚合功能,std::map 在基本功能上与 interval_map 不完全等效。因此,icl 中有一个额外的 icl::map 类模板,用于元素的映射。

下表概述了 icl 提供的主要类模板。

表 1.1 区间类模板

形式

template

静态有界

不对称

右开区间

左开区间

对称

闭区间

开区间

动态有界

离散区间

连续区间


静态有界区间总是有相同类型的区间边界,例如,对于 right_open_interval,右开边界是 [a..b)。动态有界区间可以有不同的边界。有关详细信息,请参阅关于 区间 的章节。

表 1.2 容器类模板

粒度

样式

集合

映射

区间

连接

interval_set

interval_map

分离

separate_interval_set

分割

split_interval_set

split_interval_map

元素

(std::set )

map


Std::set 放在括号中,因为它不是 ICL 的类模板。但它可以用作元素容器,在基本方面与 ICL 的区间集合行为等效。列 样式 指的是区间容器组合添加区间的不同方式。这些 组合样式 在下一节中进行描述。

当我们向区间容器添加区间或区间值对时,区间可以以不同的方式添加:区间可以连接、分割或保持分离。不同的区间组合样式通过下面的示例表格进行展示。

表 1.3 区间容器组合区间的方式

连接

分离

分割

集合

interval_set

separate_interval_set

split_interval_set

map

interval_map

split_interval_map

区间在重叠或接触时连接
(如果相关值相等)。

区间在重叠时连接,在接触时不连接。

区间在重叠时分割。
所有区间边界都保留。


表 1.4 区间组合样式示例

连接

分离

分割

集合

Interval_set A

separate_interval_set B

split_interval_set C

  {[1      3)          }
+       [2      4)
+                 [4 5)
= {[1                5)}

  {[1      3)}         }
+       [2      4)
+                 [4 5)
= {[1           4)[4 5)}

  {[1      3)          }
+       [2      4)
+                 [4 5)
= {[1 2)[2 3)[3 4)[4 5)}

map

interval_map D

split_interval_map E

  {[1      3)->1          }
+       [2      4)->1
+                 [4 5)->1
= {[1 2)[2 3)[3      5)   }
  | ->1  ->2     ->1      |

  {[1      3)->1          }
+       [2      4)->1
+                 [4 5)->1
= {[1 2)[2 3)[3 4)[4 5)   }
  | ->1  ->2  ->1  ->1    |


请注意,interval_sets ABC 代表相同的元素集 {1,2,3,4},而 interval_maps DE 代表相同的元素映射 {1->1, 2->2, 3->1, 4->1}。有关更多演示,请参见示例程序 Interval container

连接区间容器

Interval_setinterval_map 始终处于 最小表示。这在插入点或区间交集不相关的情况下很有用。因此,在大多数情况下,interval_setinterval_map 将是区间容器的首选。

分割区间容器

相反,Split_interval_setsplit_interval_map 具有 插入记忆。它们累积来自添加和交集的区间边界。这在希望用特定的时间网格(例如,月份或日历周或两者)丰富区间容器时特别有用。请参阅示例 time grids for months and weeks

分离区间容器

Separate_interval_set 实现分离样式。此样式保留永不被重叠区间通过的边界。因此,如果插入 separate_interval_set 的所有区间都来自某个永不通过月份边界的网格,那么这些边界将在 separate_interval_set 中得到保留。

14:46 15.10.2010


Next