CGAL的手柄和循环器

1、手柄

        CGAL中的大多数数据结构在其用户界面中使用Handles 的概念来引用它们存储的元素。这个概念描述了有时被称为琐碎迭代器的东西。Handle类似于指向对象的指针,提供解引用运算符*()和成员访问运算符->(),但没有像迭代器那样的递增或递减运算符。只要引用的对象不是逻辑序列的一部分,就可以使用句柄。

        句柄的模型简单指针T*、值类型为T的迭代器或循环器也是句柄。

2、范围

        CGAL中的大多数数据结构都使用迭代器范围的概念。Range和ConstRange概念封装了对迭代器范围的第一个和最后一个迭代器的访问。STL容器是Range的模型。The Boost。范围库也围绕这个概念提供了很好的支持。

3、循环器

        介绍了循环器的概念。给出了几个在迭代器和循环器之间进行转换的适配器。以下是循环器的一些有用函数。本章最后对所做的设计决策进行了讨论。有关循环器要求、提供的基类、循环器标签以及对迭代器和循环器通用算法的支持的完整描述,请参阅参考页。请注意,循环器不是STL的一部分,而是CGAL的一部分。

3.1、介绍、

        STL中迭代器的概念是为线性序列量身定制的。相反,圆形序列自然地出现在许多组合和几何结构中。例如多面体曲面和平面图,其中从顶点发出的边或小平面周围的边形成圆形序列。

        由于循环序列不允许有效的迭代器,我们引入了循环器的新概念。它们共享迭代器的大部分要求,而主要的区别是序列中没有超过末尾的位置。在迭代器和循环器之间提供了适当的适配器,以将循环器平滑地集成到STL的框架中。一个泛型包含函数的例子说明了循环器的使用。与圆形结构的通常情况一样,do-while循环是优选的,使得对于特定输入c==d,到达序列中的所有元素。

template 
bool contains( Circulator c, Circulator d, const T& value) {
  if (c != 0) {
    do {
      if (*c == value)
        return true;
    } while (++c != d);
  }
  return false;
}

        定义了三类循环器:前向、双向和随机接入循环器。给定一个循环器c,运算*c表示循环器所指的项。运算++c使循环器前进一项,-c使双向循环器后退一项。对于随机接入循环器,c+n使循环器前进n步。可以比较两个循环器是否相等。

        循环器与迭代器在可达性和范围方面有不同的概念。循环器d称为从循环器c可达,如果c可以在算子++的有限多个应用中等于d。由于序列的循环性,如果两个循环器都引用相同序列的项,则这总是正确的。特别地,c总是从c可达的。给定两个循环器c和d,范围[c,d)表示通过从c开始并推进c直到达到d而获得的所有循环器,但不包括d,对于d!=c。到目前为止,它与迭代器的范围定义相同。区别在于使用[c,c)表示循环序列中的所有项,而对于迭代器i,range[i,i)表示空范围[c,d)的行为类似于迭代器范围,可以在STL算法中使用。但是,对于循环器,需要一个额外的测试c==nullptr,当且仅当循环序列为空时,该测试返回true。对于c++,我们建议使用0而不是nullptr。

        除了概念上的简洁,发明一个与迭代器意图相似的新概念的主要原因是效率。迭代器应该是一个轻量级对象——仅仅是一个指针和一个用于推进迭代器的间接方法。尽管迭代器可以为循环序列编写,但我们不知道有什么有效的解决方案。循环序列中的遗漏超过结束的情况可以用循环顺序中的任意哨兵来解决,但这会破坏结构中的自然对称性(这本身就是个坏主意),并且项目中的额外记账和迭代器高级方法中的检查会降低效率。另一种解决方案可能在迭代器中使用更多的记账,例如,使用一个开始项、一个当前项和一种绕组数,该绕组数对于begin()-迭代器为零,对于过去-结束情况为一[1]。我们引入了允许轻量级实现的循环器的概念,CGAL支持库提供了在迭代器和循环器之间转换的适配器类(在效率上有相应的惩罚),以便将这一新概念集成到STL的框架中。

        一个严重的设计问题是与迭代器范围相比,循环器范围的语义略有变化。由于这个语义是由直观运算符++和==定义的,我们也希望为循环器保留这些运算符,因此循环器范围可以用于STL算法。这本身就是一个有用的特征,如果没有完整范围[c,c)的定义,STL算法会将其视为空范围。然而,错误的可能性可能被高估了,因为对于支持循环器的容器c来说,没有end()成员函数和std::sort(c.begin(),c.end())等表达式)将失败。

        在编译时很容易区分迭代器和循环器,这允许通用算法同时支持这两个参数。也可以使用相同的技术保护算法不受不适当参数的影响,请参阅循环器的参考页,特别是Assert_iterator()和is_empty_range()函数。 

        注意
        请注意,范围的定义与迭代器的定义不同。数据结构的接口必须声明它是使用迭代器、循环器,还是同时使用这两种方法。STL算法总是在它们的接口中只指定迭代器。迭代器接口中使用的循环器的范围[c,d)将在c!=d的时间内按预期工作。范围[c,c)将被解释为与迭代器类似的空范围,这与它应该表示的循环器全范围不同。

3.2、迭代器和循环器之间的适配器

        在迭代器范围上工作的算法不能完全通用地应用于循环器范围,只能应用于上一节中指出的子范围。以下适配器将循环器转换为迭代器,反之亦然(具有不可避免的空间和时间损失),以重新建立这种通用性。

        Container_from_circulator是一个类似容器的类,具有从循环器构建的迭代器

        Circulator_from_iterator是一个在两个迭代器范围内的循环器

        Circulator_from_container是容器的循环器

        以下示例将STL的通用std::reverse()算法应用于双向循环器c给出的序列。它使用Container_from_circulator适配器。

Circulator c; // c must be at least bidirectional.
CGAL::Container_from_circulator container(c);
std::reverse( container.begin(), container.end());

        另一个例子为int的向量定义了循环器c。然而,由于矢量中没有元素,循环器表示一个空序列。如果矢量中有元素,循环器将实现序列大小的随机访问模。 

std::vector v;
typedef CGAL::Circulator_from_iterator< std::vector::iterator > Circulator;
Circulator c( v.begin(), v.end());

3.3、循环器上的函数

        几个函数处理循环器和循环器范围。类型C表示循环器。类型IC表示循环器或迭代器。

C c, d;
IC ic1, ic2;
circulator_size(c);          // size of the sequence reachable by c
circulator_distance(c, d);   // number of elements in the range [c, d)
iterator_distance(ic1, ic2); // number of elements in the range [ic2, ic1)
is_empty_range(ic1, ic2);    // test the range [ic2, ic1) for emptiness

你可能感兴趣的:(CGAL,算法)