Boost C++ 库

...世界上最受尊敬和专家设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

Next

第一章 Boost.Icl

Joachim Faulhaber

根据 Boost 软件许可证,版本 1.0 进行分发。(参见随附文件 LICENSE_1_0.txt 或复制于 https://boost.ac.cn/LICENSE_1_0.txt

目录

简介
定义和基本示例
Icl 的类模板
区间合并样式
示例
概述
聚会
区间
动态区间
静态区间
区间容器
重叠计数器
聚会平均身高
聚会最高客人
月和周的时间网格
人力
用户组
标准复制
标准转换
自定义区间
项目
大型位集
概念
命名
方面
集合和映射
可加性、可减性和重叠聚合
映射特征
语义
排序和等价
集合
映射
收集器:集合的映射
量词:数字的映射
概念归纳
接口
类模板
所需概念
关联类型
函数概要
自定义
区间
实现
迭代大小
复杂度
就地和中缀运算符
函数参考
重载表
分段细度
键类型
构造、复制、析构
包含性
等价和排序
大小
范围
选择
加法
减法
插入
擦除
交集
对称差
迭代器相关
元素迭代
流式传输,转换
区间构造
其他区间排序
杂项区间函数
致谢
区间容器库参考
头文件 <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** 中移除。

区间在软件开发中几乎无处不在。然而,它们很容易通过一对数字编码到用户定义的类中,因此它们在大多数情况下只是 *隐式地* 使用。区间的含义很简单。它们表示上下限之间的所有元素,因此是一个集合。但与集合不同的是,区间通常不能添加到单个新区间中。如果您想将区间添加到仍然表示 *集合* 的区间集合中,您就会想到该库提供的 *区间集* 的概念。

**ICL** 的区间容器最初是在 Cortex Software GmbH 开发的,用于解决与医院信息系统中日期和时间区间计算相关的问题。具有关联值(如 *发票金额* 或 *治疗集*)的时间区间必须在统计、计费程序和治疗调度程序中进行操作。因此,**ICL** 应运而生。它从日期和时间问题域中提取有助于解决常见问题的通用代码,并且也可以应用于其他领域。

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

有关简要介绍和概述,您可以查看 **BoostCon2009** 上关于 **ICL** 的演示文稿资料 *。

**区间容器库 (ICL)** 提供 区间 和两种区间容器:区间集区间映射

  • 区间集 是一个实现为一组区间的**集合**。
  • 区间映射 是一个实现为区间值对映射的**映射**。
两个方面

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

第一个方面,称为 ***基本*** ***方面***,是更重要的一个。这意味着我们可以像使用 ***元素*** 的集合或映射一样使用 区间集* 或 区间映射。它公开了相同的功能。

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

第二个方面,称为 ***分段*** ***方面***,允许利用 区间集区间映射 的元素聚集在 ***区间*** 或 ***段*** 中的事实,我们可以对其进行迭代。

// 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);

当集合的元素以连续块的形式出现时,使用 区间集区间映射 可能是有益的:区间。这在许多问题域中显然是这种情况,尤其是在处理与日期和时间相关的计算的领域中。

可加性和可减性

std::setsmaps 不同,区间集 (interval_sets)区间映射 (interval_maps) 实现了 Addable(可加性)和 Subtractable(可减性)概念。因此,区间集 定义了一个 operator += 运算符,它自然地实现为**_集合并集_**,以及一个 operator -= 运算符,它相应地实现为**_集合差集_**。在 **Icl** 中,区间映射 也是可加和可减的。当向 区间映射 中插入一个区间值对导致该区间值对与 区间映射 中已有的区间值对发生冲突时,将加法或减法传播到 区间映射 的关联值的概念被证明是非常有效的。这种运算传播称为**_重叠聚合_**。

重叠聚合

这是一个关于小型聚会的第一个示例,它演示了 区间映射 上的**_重叠聚合_**原则。

在示例中,Mary 首先进入派对。她在时间间隔 [20:00,22:00) 内参加。Harry 稍后进入。他在 [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 += 运算符完成的,该运算符必须为 区间映射 的关联值实现。在本例中,关联值是 guest sets(客人集合)。因此,guest set 必须将 operator += 实现为集合并集。

从示例中可以看出,区间映射 既具有**_分解行为_**(在时间维度上),也具有**_累加行为_**(在关联值上)。

可加性和重叠聚合是 区间映射 上的有用特性,它们通过函数 addoperator += 实现。但您也可以将它们与_传统的_ 插入语义一起使用,其行为类似于针对区间插入进行泛化的 std::map::insert

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

  • std::set 在**_基本_**方面与 区间集 行为等效。
  • icl::map 在**_基本_**方面与 区间映射 行为等效。具体来说,icl::map 实现了**_重叠聚合_**,对于元素容器,这被称为**_冲突聚合_**。

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

表 1.1. 区间类模板

形式

模板

静态边界

非对称

右开区间

左开区间

对称

闭区间

开区间

动态边界

离散区间

连续区间


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

表 1.2. 容器类模板

粒度

样式

集合

映射

区间

连接

区间集

区间映射

分离

分离区间集

分割

分割区间集

分割区间映射

元素

(std::set)

映射


Std::set 放在括号中,因为它不是 **ICL** 的类模板。它可以用作元素容器,在其基本方面与 ICL 的区间集行为等效。“样式”列指的是区间容器组合已添加区间的方式。下一节将通过示例说明这些**_组合样式_**。

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

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

连接

分离

分割

集合

区间集

分离区间集

分割区间集

映射

区间映射

分割区间映射

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

区间在重叠时连接,而不是在接触时连接.

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


表 1.4. 区间组合样式示例

连接

分离

分割

集合

区间集 *A*

分离区间集 *B*

分割区间集 *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)}

映射

区间映射 *D*

分割区间映射 *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` *A*、*B* 和 *C* 表示相同的元素集 `{1,2,3,4}`,`interval_maps` *D* 和 *E* 表示相同的元素映射 `{1->1, 2->2, 3->1, 4->1}`。有关其他演示,请参见示例程序 区间容器

连接区间容器

区间集区间映射 始终处于**_最小表示_**状态。这在许多情况下非常有用,在这些情况下,区间的插入点或交点无关紧要。因此,在大多数情况下,区间集区间映射 将是区间容器的首选。

分割区间容器

Split_interval_setsplit_interval_map 正好相反,它们具有插入记忆。它们会累积来自添加和交集的区间边界。如果我们想要使用特定的时间网格(例如,月份或日历周,或两者)来丰富区间容器,这将特别有用。参见示例 月和周的时间网格

分离区间容器

Separate_interval_set 实现了分离样式。这种样式保留了永远不会被重叠区间穿过的边界。因此,如果插入到 separate_interval_set 中的所有区间都是从某个永远不会穿过月份边界的网格生成的,那么这些边界将在 separate_interval_set 中保留。

14:46 15.10.2010


Next