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] 注意

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

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

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

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

为了获得简洁的介绍和概述,您可能想看看 来自 BoostCon2009 的关于 ICL 的演示材料

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

两个方面

区间集合 (Interval_sets)区间映射 (interval_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);

当集合的元素以连续块的形式出现时(区间 (intervals)),使用 interval_setsinterval_maps 会很有益。这显然是许多问题领域的普遍情况,特别是在涉及日期和时间计算的领域。

可加性和可减性

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

重叠时聚合

这是一个初步的激励性示例,展示了一个非常小的派对,演示了 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 的关联值实现。在示例中,关联值是 访客 集合。因此,访客 集合 必须实现 operator += 作为集合并集。

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

interval_maps 上,可加性和重叠时聚合是通过 add 函数和 operator += 实现的有用的功能。但您也可以使用 传统插入语义,它类似于 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_setinterval_map 始终处于 最小表示 状态。这在插入点或区间交集不重要的许多情况下很有用。因此,在大多数情况下,interval_setinterval_map 将是区间容器的首选。

分割区间容器

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

分离区间容器

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

14:46 15.10.2010


Next