mirror of https://github.com/CGAL/cgal
304 lines
13 KiB
TeX
304 lines
13 KiB
TeX
\section{Software Design}
|
|
|
|
In order to be able to define a multilayer tree we first
|
|
designed the range and segment tree to have a template argument
|
|
defining the type of the sublayer tree. With this sublayer tree
|
|
type information the sublayers could be created. This approach lead to nested
|
|
template arguments, since the sublayer tree can again have a template
|
|
argument defining the sublayer. Therefore, the internal class and function
|
|
identifiers got longer than a compiler-dependent limit.
|
|
This happend already for $d=2$.
|
|
|
|
Therefore, we chose another, object oriented,
|
|
design. We defined a pure
|
|
virtual base class called \ccc{Tree_base} from which we derived
|
|
the classes \ccc{Range_tree_d} and \ccc{Segment_tree_d}.
|
|
The constructor of these classes expects an argument called
|
|
\ccc{sublayer_prototype} of type \ccc{Tree_base}.
|
|
Since class \ccc{Range_tree_d} and class
|
|
\ccc{Segment_tree_d} are derived from class \ccc{Tree_base}, one can
|
|
use an instantiation of class \ccc{Range_tree_d} or class
|
|
\ccc{Segment_tree_d} as constructor argument.
|
|
This argument defines the sublayer tree of the tree. E.g., you
|
|
can construct a \ccc{Range_tree_d} with an
|
|
instantiation of class \ccc{Segment_tree_d} as constructor
|
|
argument. You then have defined a range tree with a segment tree
|
|
as sublayer tree. Since both classes \ccc{Range_tree_d} and
|
|
\ccc{Segment_tree_d} expect a sublayer tree in their constructor
|
|
we had to derive a third class called \ccc{Tree_anchor} from
|
|
class \ccc{Tree_base} which
|
|
does not expect a constructor argument. An instantiation of this
|
|
class is used as constructor argument of class \ccc{Range_tree_d} or
|
|
\ccc{Segment_tree_d} in order to stop the recursion.
|
|
|
|
All classes provide a \ccc{clone()} function which returns an
|
|
instance (a copy) of the same tree type. The \ccc{clone()}
|
|
function of the \ccc{sublayer_prototype} is called in the
|
|
construction of the tree. In case that the sublayer tree again
|
|
has a sublayer, it also has a \ccc{sublayer_prototype} which is
|
|
also cloned and so on. Thus, a call to the \ccc{clone()} function
|
|
generates a sublayer tree which has the complete knowledge about
|
|
its sublayer tree.
|
|
|
|
%Now a tree is created with a prototype of the sublayer
|
|
%tree. With this prototype the sublayer tree can be cloned.
|
|
%More precisely, the constructor for the range and segment tree
|
|
%gets an argument called \ccc{sublayer_prototype}, which defines not
|
|
%only the type of the sublayer tree, but also the type of the
|
|
%sublayer tree
|
|
%of the sublayer tree and so on.
|
|
%Therefore, the type of this argument has to be specified.
|
|
%This type either is of type \ccc{Range_tree_d}, \ccc{Segment_tree_d},
|
|
%or another tree data structure, that can be combined. In order to
|
|
%realize this, we made use of the OOP paradigm and defined a pure
|
|
%virtual base class called \ccc{Tree_base} from which we derived
|
|
%class \ccc{Range_tree_d} and class \ccc{Segment_tree_d}. The
|
|
%type of the constructor argument \ccc{sublayer_prototype} which
|
|
%defines the prototype is \ccc{Tree_base}. Thus, we can assign an
|
|
%object of type \ccc{Range_tree_d} or \ccc{Segment_tree_d} to the
|
|
%variable \ccc{sublayer_prototype}. Whenever a member function of
|
|
%\ccc{sublayer_prototype} is called, the corresponding function in
|
|
%class \ccc{Range_tree_d} is called if the real type of the
|
|
%\ccc{sublayer_prototype} is \ccc{Range_tree_d}. Otherwise the
|
|
%corresponding function in class \ccc{Segment_tree_d} is called.%
|
|
%
|
|
%There is a third class derived from class \ccc{Tree_base} which
|
|
%is called \ccc{Tree_anchor}. Since the \ccc{Range_tree_d} and
|
|
%\ccc{Segment_tree_d} classes are defined to have a sublayer tree,
|
|
%we need a sublayer which does not again have a sublayer tree, in
|
|
%order to stop the recursion. Class \ccc{Tree_anchor} plays this
|
|
%role.
|
|
|
|
%When the constructor of a \ccc{Range_tree_d} or
|
|
%\ccc{Segment_tree_d} class is called, the following happens. The
|
|
%constructor gets a prototype of its sublayer tree, which either
|
|
%is a \ccc{Range_tree_d},
|
|
%\ccc{Segment_tree_d}, or \ccc{Tree_anchor}. In the constructor a
|
|
%variable \ccc{sublayer_tree} is initialized with a clone of this
|
|
%prototype. Therefore, the \ccc{clone()} function of the
|
|
%prototype is called. If the prototype itself has again a sublayer
|
|
%tree, then its constructor is called with argument
|
|
%\ccc{sublayer_tree} which is the prototype of the sublayer tree
|
|
%of the prototype. This prototype is then cloned again and so on.
|
|
|
|
The trees allow to perform
|
|
window queries, enclosing queries, and inverse range queries on
|
|
the keys. Clearly, an inverse range query makes only sense in the
|
|
segment tree.
|
|
In order to perform an inverse range query, a range query of
|
|
$\epsilon$ width has to be performed. We prefered not to offer an
|
|
extra function for this sort of query, since the inverse range
|
|
query is a special case of the range query. Furthermore, offering
|
|
an inverse range query in the segment tree class implies offering this
|
|
function also in the range tree class and having an extra item in
|
|
the traits class that accesses the inverse range query point.
|
|
|
|
The trees are templatized with three arguments: \ccStyle{Data, Window}
|
|
and \ccStyle{Traits}. Type \ccStyle{Data} defines
|
|
the input data type and type \ccStyle{Window} defines the query
|
|
window type. The tree uses a well defined set of functions in
|
|
order to access data. These functions have to be provided by
|
|
class \ccStyle{Traits}.
|
|
%The requirements are described in
|
|
%Section~\ref{TreeInterface}.
|
|
|
|
|
|
The design partly follows the {\em prototype design pattern}
|
|
in~\cite{cgal:ghjv-dpero-95}. In comparison to our first approach
|
|
using templates we want to note the following: In this approach
|
|
the sublayer type is defined in
|
|
use of object oriented programming at run time, while in the
|
|
approach using templates, the sublayer type is defined at compile
|
|
time.
|
|
|
|
The runtime overhead caused in use of virtual member
|
|
functions in this object oriented design is negligible since all virtual
|
|
functions are non trivial.
|
|
\begin{ccTexOnly}
|
|
The design concept is illustrated in Figure~\ref{rangesegmentdesign}.
|
|
\end{ccTexOnly}
|
|
\begin{ccHtmlOnly}
|
|
The design concept is illustrated in the figure below.
|
|
\end{ccHtmlOnly}
|
|
|
|
\begin{ccTexOnly}
|
|
\begin{sidewaysfigure}
|
|
%\begin{figure}[htbp]
|
|
\psfrag{A}{{\em Data}}
|
|
\psfrag{B}{{\em Window}}
|
|
\psfrag{C}{{\em Tree\_traits}}
|
|
\psfrag{D}{{\em Tree\_base$<$Data,Window$>$}}
|
|
\psfrag{E}{\small\parbox{8cm}{\em Tree\_base$<$Data,Window$>$
|
|
*sublayer\_tree;\\
|
|
Tree\_base(Tree\_base$\&$~sublayer\_prototype);\\
|
|
Tree\_base *clone();\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm}virtual bool make\_tree(T$\&$~begin, T$\&$~end);\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} virtual T window\_query(Window$\&$~w, T out);}}
|
|
\psfrag{F}{{\em Range\_tree\_d$<$Tree\_traits$>$}}
|
|
\psfrag{G}{\small\parbox{6cm}{\em
|
|
Range\_tree\_d(Tree\_base$\&$~sublayer\_proto){}\\
|
|
Range\_tree\_d $\star$clone(){}\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} bool make\_tree(T$\&$~begin, T$\&$~end){}\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} T window\_query(Window$\&$~w, T out){}}}
|
|
\psfrag{H}{{\em Segment\_tree\_d$<$Tree\_traits$>$}}
|
|
\psfrag{I}{\small\hspace*{-.1cm}\parbox{6cm}{\em
|
|
Segment\_tree\_d(Tree\_base$\&$~slayer\_proto){}\\
|
|
Segment\_tree\_d $\star$clone(){}\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} bool make\_tree(T$\&$~begin, T$\&$~end){}\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} T window\_query(Window$\&$~w, T out){}}}
|
|
\psfrag{J}{{\em Tree\_anchor}}
|
|
\psfrag{K}{\small\parbox{6cm}{\em
|
|
Tree\_anchor(){}\\
|
|
Tree\_anchor $\star$clone(){}\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} bool make\_tree(T$\&$~begin, T$\&$~end){}\\
|
|
template$<$class T$>$\\
|
|
\hspace*{.2cm} T window\_query(Window$\&$~w, T out){}}}
|
|
\includegraphics[width=\textwidth,clip]{SearchStructures/rangesegmentdesign}
|
|
\caption{\label{rangesegmentdesign} Design of the range and
|
|
segment tree data structure. The symbol triangle means
|
|
that the lower class is derived from the upper class. }
|
|
%\end{figure}
|
|
\end{sidewaysfigure}
|
|
\end{ccTexOnly}
|
|
|
|
\begin{ccHtmlOnly}
|
|
<img border=0 width=400 height=200 src="./rsd.gif" alt="Design of the range and
|
|
segment tree data structure. The symbol triangle means
|
|
that the lower class is derived from the upper class.">
|
|
\end{ccHtmlOnly}
|
|
|
|
E.g.\ in order to define a two dimensional multilayer tree, which
|
|
consists of a range tree in the first dimension and a segment
|
|
tree in the second dimension we proceed as follows: We construct
|
|
an object of type \ccc{Tree_anchor} which stops the
|
|
recursion. Then we construct an object of type \ccc{Segment_tree_d},
|
|
which gets as prototype argument our object of type
|
|
\ccc{Tree_anchor}. After that, we define an object of type
|
|
\ccc{Range_tree_d} which is constructed with the object of type
|
|
\ccc{Segment_tree_d} as prototype argument.
|
|
The following piece of code illustrates
|
|
the construction of the two-dimensional multilayer tree.
|
|
%This example is illustrated in Algorithm~\ref{rangesegex}.
|
|
|
|
\begin{verbatim}
|
|
int main(){
|
|
Tree_Anchor *anchor=new Tree_Anchor;
|
|
Segment_Tree_d *segment_tree = new Segment_Tree_d(*anchor);
|
|
Range_Tree_d *range_segment_tree = new Range_Tree_d(*segment_tree);
|
|
/* let data_items be a list of Data items */
|
|
range_segment_tree->make_tree(data_items.begin(),data_items.end());
|
|
}
|
|
\end{verbatim}
|
|
|
|
Here, class \ccc{Tree_Anchor, Segment_Tree_d}, and
|
|
\ccc{Range_Tree_d} are defined by \ccc{typedef}s:
|
|
|
|
\begin{verbatim}
|
|
typedef Tree_anchor<Data,Window> Tree_Anchor;
|
|
typedef Segment_tree_d<Data,Window,Interval_traits> Segment_Tree_d;
|
|
typedef Range_tree_d<Data,Window,Point_traits> Range_Tree_d;
|
|
\end{verbatim}
|
|
|
|
|
|
%int main(){
|
|
% Tree_anchor<Data,Window> *anchor=new Tree_anchor<Data,Window>;
|
|
% Segment_tree_d<Data,Window,Interval_traits> *segment_tree =
|
|
% new Segment_tree_d<Data,Window,Interval_traits>(*anchor);
|
|
% Range_tree_d<Data,Window,Point_traits> *range_segment_tree =
|
|
% new Range_tree_d<Data,Window,Point_traits>(*segment_tree);
|
|
% /* let data_items be a list of Data items */
|
|
% range_segment_tree->make_tree(data_items.begin(),data_items.end());
|
|
%}
|
|
|
|
%The design is illustrated in
|
|
%Figure~\ref{fig:rangesegmentdesign}.
|
|
|
|
|
|
|
|
|
|
Class \ccc{Tree\_base} and class
|
|
\ccc{Tree_anchor} get two template arguments: a class
|
|
\ccc{Data} which defines the type of data that is stored in
|
|
the tree, and a class \ccc{Window} which defines the type of a query
|
|
range.
|
|
The derived classes \ccc{Range_tree_d} and \ccc{Segment_tree_d}
|
|
additionally get an argument called
|
|
\ccc{Tree_traits} which defines the interface between the
|
|
\ccc{Data} and the tree. Let the \ccc{Data} type be a $d$-dimensional
|
|
tuple, which is either a point data or an interval data in each
|
|
dimension. Then, the class \ccc{Tree_traits} provides accessors to
|
|
the point (resp. interval) data of that tree layer and a compare
|
|
function. Remind our example of the two-dimensional tree which
|
|
is a range tree in the first dimension and
|
|
a segment tree in the second dimension. Then, the
|
|
\ccc{Tree_traits} class template argument of class
|
|
\ccc{Segment_tree_d} defines an accessor to the interval data of
|
|
the \ccc{Data}, and the
|
|
\ccc{Tree_traits} class template argument of class
|
|
\ccc{Range_tree_d} defines an accessor to the point data of
|
|
\ccc{Data}.
|
|
An example implementation for these classes is listed below.
|
|
%(see Algorithm~\ref{traitsex}).
|
|
|
|
\begin{verbatim}
|
|
struct Data{
|
|
int min,max; /* interval data */
|
|
double point; /* point data */
|
|
};
|
|
|
|
struct Window{
|
|
int min,max;
|
|
double min_point, max_point;
|
|
};
|
|
|
|
class Point_traits{
|
|
public:
|
|
typedef double Key;
|
|
Key get_key(Data& d){return d.point;} /*key accessor */
|
|
Key get_left(Window& w){return w.min_point;}
|
|
Key get_right(Window& w){return w.max_point;}
|
|
bool comp(Key& key1, Key& key2){return (key1 < key2);}
|
|
}
|
|
|
|
class Interval_traits{
|
|
public:
|
|
typedef int Key;
|
|
Key get_left(Data& d){return d.min;}
|
|
Key get_right(Data& d){return d.max;}
|
|
Key get_left_win(Window& w){return w.min;}
|
|
Key get_right_win(Window& w){return w.max;}
|
|
bool comp(Key& key1, Key& key2){return (key1 < key2);}
|
|
}
|
|
\end{verbatim}
|
|
|
|
\section{Creating an Arbitrary Multilayer Tree}
|
|
\label{general}
|
|
|
|
Now let us have a closer look on how a multilayer tree is built.
|
|
In case of creating a $d$-dimensional tree, we handle a
|
|
sequence of arbitrary data
|
|
items, where each item defines a $d$-dimensional interval, point
|
|
or other object. The tree is constructed with an iterator over
|
|
this structure. In the $i$-th layer, the tree is
|
|
built with respect to the data slot that defines the $i$-th
|
|
dimension. Therefore, we need to define which data slot
|
|
corresponds to which dimension.
|
|
In addition we want our tree to work with arbitrary data items.
|
|
This requires an
|
|
adaptor between the algorithm and the data item. This is resolved
|
|
by the use of traits classes, implemented in
|
|
form of a traits class using
|
|
function objects.
|
|
These classes provide
|
|
access functions to a specified data slot of a data item.
|
|
A $d$-dimensional tree is then defined separately for each layer by
|
|
defining a traits class for each layer.
|
|
|