aGrUM
0.20.3
a C++ library for (probabilistic) graphical models
indexedTree_tpl.h
Go to the documentation of this file.
1
/**
2
*
3
* Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4
* info_at_agrum_dot_org
5
*
6
* This library is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public License
17
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18
*
19
*/
20
21
22
/**
23
* @file
24
* @brief Implementation of tree data structures
25
*
26
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27
*/
28
29
// to ease IDE parser
30
#
include
<
agrum
/
tools
/
core
/
indexedTree
.
h
>
31
32
namespace
gum
{
33
/* =========================================================================*/
34
/* =========================================================================*/
35
/* === IMPLEMENTATION OF NODES FOR GENERIC TREE (DATA) STRUCTURE === */
36
/* =========================================================================*/
37
/* =========================================================================*/
38
39
// creates a tree with one node (with or without data)
40
41
template
<
typename
Key,
typename
Data >
42
IndexedTree< Key, Data >::IndexedTree(
const
Key& theKey, Data* theData) :
43
key(theKey), data(theData), parent(0) {
44
// for debugging purposes
45
GUM_CONSTRUCTOR(IndexedTree);
46
}
47
48
// creates a tree with one node (with or without data)
49
50
template
<
typename
Key
,
typename
Data
>
51
IndexedTree
<
Key
,
Data
>::
IndexedTree
(
Data
*
theData
) :
data
(
theData
),
parent
(0) {
52
// for debugging purposes
53
GUM_CONSTRUCTOR
(
IndexedTree
);
54
}
55
56
// creates a tree with one node with data
57
58
template
<
typename
Key
,
typename
Data
>
59
IndexedTree
<
Key
,
Data
>::
IndexedTree
(
const
Key
&
theKey
,
const
Data
&
theData
) :
60
key
(
theKey
),
data
(
new
Data
(
theData
)),
parent
(0) {
61
// for debugging purposes
62
GUM_CONSTRUCTOR
(
IndexedTree
);
63
}
64
65
// copy constructor
66
67
template
<
typename
Key
,
typename
Data
>
68
IndexedTree
<
Key
,
Data
>::
IndexedTree
(
const
IndexedTree
<
Key
,
Data
>&
from
) :
69
key
(
from
.
key
),
data
(0),
parent
(0) {
70
// for debugging purposes
71
GUM_CONS_CPY
(
IndexedTree
);
72
73
try
{
74
// create the data of the node
75
if
(
from
.
data
)
data
=
new
Data
(*
from
.
data
);
76
77
// create and link properly the children
78
children
=
from
.
children
;
79
80
for
(
HashTableIteratorSafe
<
Key
,
IndexedTree
<
Key
,
Data
> >
iter
=
children
.
begin
();
81
iter
!=
children
.
end
();
82
++
iter
)
83
iter
->
parent
=
this
;
84
}
catch
(...) {
85
if
(
data
)
delete
data
;
86
87
children
.
clear
();
88
89
throw
;
90
}
91
}
92
93
// copy operator
94
95
template
<
typename
Key
,
typename
Data
>
96
IndexedTree
<
Key
,
Data
>&
97
IndexedTree
<
Key
,
Data
>::
operator
=(
const
IndexedTree
<
Key
,
Data
>&
from
) {
98
// avoid self assignment
99
if
(
this
!= &
from
) {
100
// for debugging purposes
101
GUM_OP_CPY
(
IndexedTree
);
102
103
try
{
104
key
=
from
.
key
;
105
106
if
(
data
)
delete
data
;
107
108
if
(
from
.
data
)
109
data
=
new
Data
(*
from
.
data
);
110
else
111
data
= 0;
112
113
children
=
from
.
children
;
114
115
for
(
HashTableIteratorSafe
<
Key
,
IndexedTree
<
Key
,
Data
> >
iter
=
children
.
begin
();
116
iter
!=
children
.
end
();
117
++
iter
)
118
iter
->
parent
=
this
;
119
}
catch
(...) {
120
if
(
data
)
delete
data
;
121
122
children
.
clear
();
123
124
throw
;
125
}
126
}
127
128
return
*
this
;
129
}
130
131
// destructor
132
133
template
<
typename
Key
,
typename
Data
>
134
IndexedTree
<
Key
,
Data
>::~
IndexedTree
() {
135
// for debugging purposes
136
GUM_DESTRUCTOR
(
IndexedTree
);
137
138
if
(
data
)
delete
data
;
139
}
140
141
// adds a new node into the tree
142
143
template
<
typename
Key
,
typename
Data
>
144
void
IndexedTree
<
Key
,
Data
>::
insertNode
(
const
std
::
vector
<
Key
>&
index
,
const
Data
*
theData
) {
145
// parse the tree until we are on the proper index. Then, insert the new
146
// node.
147
// current_node is a pointer on the node of the tree corresponding to
148
// position
149
// i in vector index. When i+2 < index.size(), we need go down into the tree
150
// structure before we can insert the new node
151
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
152
unsigned
int
i
;
153
154
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
155
// if the node that should be on the path between the root of the tree and
156
// the node that we wish to insert does not exist, create it
157
if
(!
children
.
exists
(
index
[
i
])) {
158
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
159
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
160
new_node
->
parent
=
this
;
161
current_node
=
new_node
;
162
}
else
163
current_node
=
current_node
->
children
[
index
[
i
]];
164
}
165
166
// here, we can insert the new node. if ind + 1 == index.size(), this means
167
// that
168
// the index vector was not empty, else the vector was empty and we are at
169
// the
170
// root of the tree
171
if
(
i
+ 1 ==
index
.
size
()) {
172
// if the node to be inserted already exist, throw an exception
173
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
174
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
)
175
}
176
177
// here, the node to be inserted does not exist, so we must create it
178
IndexedTree
<
Key
,
Data
>*
new_node
179
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
const_cast
<
Data
* >(
theData
));
180
181
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
182
183
new_node
->
parent
=
current_node
;
184
}
else
{
185
// here, the node to be inserted is the root of the tree (so it already
186
// exists)
187
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
)
188
}
189
}
190
191
// adds a new node into the tree
192
193
template
<
typename
Key
,
typename
Data
>
194
void
IndexedTree
<
Key
,
Data
>::
insertNode
(
const
std
::
vector
<
Key
>&
index
,
const
Data
&
theData
) {
195
// parse the tree until we are on the proper index. Then, insert the new
196
// node.
197
// current_node is a pointer on the node of the tree corresponding to
198
// position
199
// i in vector index. When i+2 < index.size(), we need go down into the tree
200
// structure before we can insert the new node
201
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
202
unsigned
int
i
;
203
204
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
205
// if the node that should be on the path between the root of the tree and
206
// the node that we wish to insert does not exist, create it
207
if
(!
children
.
exists
(
index
[
i
])) {
208
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
209
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
210
new_node
->
parent
=
this
;
211
current_node
=
new_node
;
212
}
else
213
current_node
=
current_node
->
children
[
index
[
i
]];
214
}
215
216
// here, we can insert the new node. if ind + 1 == index.size(), this means
217
// that
218
// the index vector was not empty, else the vector was empty and we are at
219
// the
220
// root of the tree
221
if
(
i
+ 1 ==
index
.
size
()) {
222
// if the node to be inserted already exist, throw an exception
223
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
224
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
)
225
}
226
227
// here, the node to be inserted does not exist, so we must create it
228
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
theData
);
229
230
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
231
232
new_node
->
parent
=
current_node
;
233
}
else
{
234
// here, the node to be inserted is the root of the tree (so it already
235
// exists)
236
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
)
237
}
238
}
239
240
// updates the value of a node (or adds it if it does not already exist)
241
242
template
<
typename
Key
,
typename
Data
>
243
void
IndexedTree
<
Key
,
Data
>::
setNode
(
const
std
::
vector
<
Key
>&
index
,
Data
*
theData
) {
244
// parse the tree until we are on the proper index. Then, insert the new
245
// node.
246
// current_node is a pointer on the node of the tree corresponding to
247
// position
248
// i in vector index. When i+2 < index.size(), we need go down into the tree
249
// structure before we can insert the new node
250
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
251
unsigned
int
i
;
252
253
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
254
// if the node that should be on the path between the root of the tree and
255
// the node that we wish to insert does not exist, create it
256
if
(!
children
.
exists
(
index
[
i
])) {
257
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
258
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
259
new_node
->
parent
=
this
;
260
current_node
=
new_node
;
261
}
else
262
current_node
=
current_node
->
children
[
index
[
i
]];
263
}
264
265
// here, we can set the new node. if ind + 1 == index.size(), this means
266
// that
267
// the index vector was not empty, else the vector was empty and we are at
268
// the
269
// root of the tree
270
if
(
i
+ 1 ==
index
.
size
()) {
271
// if the node to be set does not exist, create it, else modify it
272
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
273
IndexedTree
<
Key
,
Data
>*
node
=
current_node
->
children
[
index
[
i
]];
274
275
if
(
node
->
data
)
delete
node
->
data
;
276
277
node
->
data
=
theData
;
278
}
else
{
279
// here, the node tobe set does not exist, so we must create it
280
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
theData
);
281
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
282
new_node
->
parent
=
current_node
;
283
}
284
}
else
{
285
// here, the node to be set is the root of the tree (so it does already
286
// exist
287
if
(
data
)
delete
data
;
288
289
data
=
theData
;
290
}
291
}
292
293
// updates the value of a node (or adds it if it does not already exist)
294
295
template
<
typename
Key
,
typename
Data
>
296
void
IndexedTree
<
Key
,
Data
>::
setNode
(
const
std
::
vector
<
Key
>&
index
,
const
Data
&
theData
) {
297
// parse the tree until we are on the proper index. Then, insert the new
298
// node.
299
// current_node is a pointer on the node of the tree corresponding to
300
// position
301
// i in vector index. When i+2 < index.size(), we need go down into the tree
302
// structure before we can insert the new node
303
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
304
unsigned
int
i
;
305
306
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
307
// if the node that should be on the path between the root of the tree and
308
// the node that we wish to insert does not exist, create it
309
if
(!
children
.
exists
(
index
[
i
])) {
310
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
311
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
312
new_node
->
parent
=
this
;
313
current_node
=
new_node
;
314
}
else
315
current_node
=
current_node
->
children
[
index
[
i
]];
316
}
317
318
// here, we can set the new node. if ind + 1 == index.size(), this means
319
// that
320
// the index vector was not empty, else the vector was empty and we are at
321
// the
322
// root of the tree
323
if
(
i
+ 1 ==
index
.
size
()) {
324
// if the node to be set does not exist, create it, else modify it
325
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
326
IndexedTree
<
Key
,
Data
>*
node
=
current_node
->
children
[
index
[
i
]];
327
328
if
(
node
->
data
)
delete
node
->
data
;
329
330
node
->
data
=
new
Data
(
theData
);
331
}
else
{
332
// here, the node tobe set does not exist, so we must create it
333
IndexedTree
<
Key
,
Data
>*
new_node
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
theData
);
334
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
335
new_node
->
parent
=
current_node
;
336
}
337
}
else
{
338
// here, the node to be set is the root of the tree (so it does already
339
// exist
340
if
(
data
)
delete
data
;
341
342
data
=
new
Data
(
theData
);
343
}
344
}
345
346
// returns the value of a given test from the cache
347
348
template
<
typename
Key
,
typename
Data
>
349
INLINE
Data
&
IndexedTree
<
Key
,
Data
>::
getData
(
const
std
::
vector
<
Key
>&
index
)
const
{
350
IndexedTree
<
Key
,
Data
>*
current_node
=
const_cast
<
IndexedTree
<
Key
,
Data
>* >(
this
);
351
352
for
(
unsigned
int
i
= 0;
i
<
index
.
size
(); ++
i
)
353
current_node
=
current_node
->
children
[
index
[
i
]];
354
355
if
(
data
== 0) {
GUM_ERROR
(
NotFound
,
"the datum could not be found"
) }
356
357
return
*(
current_node
->
data
);
358
}
359
360
// returns a given node of the tree
361
362
template
<
typename
Key
,
typename
Data
>
363
INLINE
IndexedTree
<
Key
,
Data
>&
364
IndexedTree
<
Key
,
Data
>::
getNode
(
const
std
::
vector
<
Key
>&
index
)
const
{
365
IndexedTree
<
Key
,
Data
>*
current_node
=
const_cast
<
IndexedTree
<
Key
,
Data
>* >(
this
);
366
367
for
(
unsigned
int
i
= 0;
i
<
index
.
size
(); ++
i
)
368
current_node
=
current_node
->
children
[
index
[
i
]];
369
370
return
*
current_node
;
371
}
372
373
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643