forked from wangchen/Programming-Game-AI-by-Example-src
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSparseGraph.h
849 lines (671 loc) · 24.4 KB
/
SparseGraph.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
#ifndef SPARSEGRAPH_H
#define SPARSEGRAPH_H
#pragma warning (disable:4786)
//------------------------------------------------------------------------
//
// Name: SparseGraph.h
//
// Desc: Graph class using the adjacency list representation.
//
// Author: Mat Buckland (fup@ai-junkie.com)
//
//------------------------------------------------------------------------
#include <vector>
#include <list>
#include <cassert>
#include <string>
#include <iostream>
#include "2D/Vector2D.h"
#include "misc/utils.h"
#include "graph/NodeTypeEnumerations.h"
template <class node_type, class edge_type>
class SparseGraph
{
public:
//enable easy client access to the edge and node types used in the graph
typedef edge_type EdgeType;
typedef node_type NodeType;
//a couple more typedefs to save my fingers and to help with the formatting
//of the code on the printed page
typedef std::vector<node_type> NodeVector;
typedef std::list<edge_type> EdgeList;
typedef std::vector<EdgeList> EdgeListVector;
private:
//the nodes that comprise this graph
NodeVector m_Nodes;
//a vector of adjacency edge lists. (each node index keys into the
//list of edges associated with that node)
EdgeListVector m_Edges;
//is this a directed graph?
bool m_bDigraph;
//the index of the next node to be added
int m_iNextNodeIndex;
//returns true if an edge is not already present in the graph. Used
//when adding edges to make sure no duplicates are created.
bool UniqueEdge(int from, int to)const;
//iterates through all the edges in the graph and removes any that point
//to an invalidated node
void CullInvalidEdges();
public:
//ctor
SparseGraph(bool digraph): m_iNextNodeIndex(0), m_bDigraph(digraph){}
//returns the node at the given index
const NodeType& GetNode(int idx)const;
//non const version
NodeType& GetNode(int idx);
//const method for obtaining a reference to an edge
const EdgeType& GetEdge(int from, int to)const;
//non const version
EdgeType& GetEdge(int from, int to);
//retrieves the next free node index
int GetNextFreeNodeIndex()const{return m_iNextNodeIndex;}
//adds a node to the graph and returns its index
int AddNode(node_type node);
//removes a node by setting its index to invalid_node_index
void RemoveNode(int node);
//Use this to add an edge to the graph. The method will ensure that the
//edge passed as a parameter is valid before adding it to the graph. If the
//graph is a digraph then a similar edge connecting the nodes in the opposite
//direction will be automatically added.
void AddEdge(EdgeType edge);
//removes the edge connecting from and to from the graph (if present). If
//a digraph then the edge connecting the nodes in the opposite direction
//will also be removed.
void RemoveEdge(int from, int to);
//sets the cost of an edge
void SetEdgeCost(int from, int to, double cost);
//returns the number of active + inactive nodes present in the graph
int NumNodes()const{return m_Nodes.size();}
//returns the number of active nodes present in the graph (this method's
//performance can be improved greatly by caching the value)
int NumActiveNodes()const
{
int count = 0;
for (unsigned int n=0; n<m_Nodes.size(); ++n) if (m_Nodes[n].Index() != invalid_node_index) ++count;
return count;
}
//returns the total number of edges present in the graph
int NumEdges()const
{
int tot = 0;
for (EdgeListVector::const_iterator curEdge = m_Edges.begin();
curEdge != m_Edges.end();
++curEdge)
{
tot += curEdge->size();
}
return tot;
}
//returns true if the graph is directed
bool isDigraph()const{return m_bDigraph;}
//returns true if the graph contains no nodes
bool isEmpty()const{return m_Nodes.empty();}
//returns true if a node with the given index is present in the graph
bool isNodePresent(int nd)const;
//returns true if an edge connecting the nodes 'to' and 'from'
//is present in the graph
bool isEdgePresent(int from, int to)const;
//methods for loading and saving graphs from an open file stream or from
//a file name
bool Save(const char* FileName)const;
bool Save(std::ofstream& stream)const;
bool Load(const char* FileName);
bool Load(std::ifstream& stream);
//clears the graph ready for new node insertions
void Clear(){m_iNextNodeIndex = 0; m_Nodes.clear(); m_Edges.clear();}
void RemoveEdges()
{
for (EdgeListVector::iterator it = m_Edges.begin(); it != m_Edges.end(); ++it)
{
it->clear();
}
}
//non const class used to iterate through all the edges connected to a specific node.
class EdgeIterator
{
private:
typename EdgeList::iterator curEdge;
SparseGraph<node_type, edge_type>& G;
const int NodeIndex;
public:
EdgeIterator(SparseGraph<node_type, edge_type>& graph,
int node): G(graph),
NodeIndex(node)
{
/* we don't need to check for an invalid node index since if the node is
invalid there will be no associated edges
*/
curEdge = G.m_Edges[NodeIndex].begin();
}
EdgeType* begin()
{
curEdge = G.m_Edges[NodeIndex].begin();
return &(*curEdge);
}
EdgeType* next()
{
++curEdge;
/* avega */
if (end()) {
return &(*(std::prev(curEdge)));
}
/* avega */
return &(*curEdge);
}
//return true if we are at the end of the edge list
bool end()
{
return (curEdge == G.m_Edges[NodeIndex].end());
}
};
friend class EdgeIterator;
//const class used to iterate through all the edges connected to a specific node.
class ConstEdgeIterator
{
private:
typename EdgeList::const_iterator curEdge;
const SparseGraph<node_type, edge_type>& G;
const int NodeIndex;
public:
ConstEdgeIterator(const SparseGraph<node_type, edge_type>& graph,
int node): G(graph),
NodeIndex(node)
{
/* we don't need to check for an invalid node index since if the node is
invalid there will be no associated edges
*/
curEdge = G.m_Edges[NodeIndex].begin();
}
const EdgeType* begin()
{
curEdge = G.m_Edges[NodeIndex].begin();
return &(*curEdge);
}
const EdgeType* next()
{
++curEdge;
/* avega */
if (end()) {
return &(*(std::prev(curEdge)));
}
/* avega */
return &(*curEdge);
}
//return true if we are at the end of the edge list
bool end()
{
//EdgeList::const_iterator next_edge = curEdge + ;
return (curEdge == G.m_Edges[NodeIndex].end());
}
};
friend class ConstEdgeIterator;
//non const class used to iterate through the nodes in the graph
class NodeIterator
{
private:
typename NodeVector::iterator curNode;
SparseGraph<node_type, edge_type>& G;
//if a graph node is removed, it is not removed from the
//vector of nodes (because that would mean changing all the indices of
//all the nodes that have a higher index). This method takes a node
//iterator as a parameter and assigns the next valid element to it.
void GetNextValidNode(typename NodeVector::iterator& it)
{
if ( curNode == G.m_Nodes.end() || it->Index() != invalid_node_index) return;
while ( (it->Index() == invalid_node_index) )
{
++it;
if (curNode == G.m_Nodes.end()) break;
}
}
public:
NodeIterator(SparseGraph<node_type, edge_type> &graph):G(graph)
{
curNode = G.m_Nodes.begin();
}
node_type* begin()
{
curNode = G.m_Nodes.begin();
GetNextValidNode(curNode);
return &(*curNode);
}
node_type* next()
{
++curNode;
GetNextValidNode(curNode);
/* avega */
if (end()) {
return &(*(std::prev(curNode)));
}
/* avega */
return &(*curNode);
}
bool end()
{
return (curNode == G.m_Nodes.end());
}
};
friend class NodeIterator;
//const class used to iterate through the nodes in the graph
class ConstNodeIterator
{
private:
typename NodeVector::const_iterator curNode;
const SparseGraph<node_type, edge_type>& G;
//if a graph node is removed or switched off, it is not removed from the
//vector of nodes (because that would mean changing all the indices of
//all the nodes that have a higher index. This method takes a node
//iterator as a parameter and assigns the next valid element to it.
void GetNextValidNode(typename NodeVector::const_iterator& it)
{
if ( curNode == G.m_Nodes.end() || it->Index() != invalid_node_index) return;
while ( (it->Index() == invalid_node_index) )
{
++it;
if (curNode == G.m_Nodes.end()) break;
}
}
public:
ConstNodeIterator(const SparseGraph<node_type, edge_type> &graph):G(graph)
{
curNode = G.m_Nodes.begin();
}
const node_type* begin()
{
curNode = G.m_Nodes.begin();
GetNextValidNode(curNode);
return &(*curNode);
}
const node_type* next()
{
++curNode;
GetNextValidNode(curNode);
/* avega */
if (end()) {
return &(*(std::prev(curNode)));
}
/* avega */
return &(*curNode);
}
bool end()
{
return (curNode == G.m_Nodes.end());
}
};
friend class ConstNodeIterator;
};
//--------------------------- isNodePresent --------------------------------
//
// returns true if a node with the given index is present in the graph
//--------------------------------------------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::isNodePresent(int nd)const
{
if ( (m_Nodes[nd].Index() == invalid_node_index) || (nd >= m_Nodes.size()))
{
return false;
}
else return true;
}
//--------------------------- isEdgePresent --------------------------------
//
// returns true if an edge with the given from/to is present in the graph
//--------------------------------------------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::isEdgePresent(int from, int to)const
{
if (isNodePresent(from) && isNodePresent(from))
{
for (EdgeList::const_iterator curEdge = m_Edges[from].begin();
curEdge != m_Edges[from].end();
++curEdge)
{
if (curEdge->To() == to) return true;
}
return false;
}
else return false;
}
//------------------------------ GetNode -------------------------------------
//
// const and non const methods for obtaining a reference to a specific node
//----------------------------------------------------------------------------
template <class node_type, class edge_type>
const node_type& SparseGraph<node_type, edge_type>::GetNode(int idx)const
{
assert( (idx < (int)m_Nodes.size()) &&
(idx >=0) &&
"<SparseGraph::GetNode>: invalid index");
return m_Nodes[idx];
}
//non const version
template <class node_type, class edge_type>
node_type& SparseGraph<node_type, edge_type>::GetNode(int idx)
{
assert( (idx < (int)m_Nodes.size()) &&
(idx >=0) &&
"<SparseGraph::GetNode>: invalid index");
return m_Nodes[idx];
}
//------------------------------ GetEdge -------------------------------------
//
// const and non const methods for obtaining a reference to a specific edge
//----------------------------------------------------------------------------
template <class node_type, class edge_type>
const edge_type& SparseGraph<node_type, edge_type>::GetEdge(int from, int to)const
{
assert( (from < m_Nodes.size()) &&
(from >=0) &&
m_Nodes[from].Index() != invalid_node_index &&
"<SparseGraph::GetEdge>: invalid 'from' index");
assert( (to < m_Nodes.size()) &&
(to >=0) &&
m_Nodes[to].Index() != invalid_node_index &&
"<SparseGraph::GetEdge>: invalid 'to' index");
for (EdgeList::const_iterator curEdge = m_Edges[from].begin();
curEdge != m_Edges[from].end();
++curEdge)
{
if (curEdge->To() == to) return *curEdge;
}
assert (0 && "<SparseGraph::GetEdge>: edge does not exist");
}
//non const version
template <class node_type, class edge_type>
edge_type& SparseGraph<node_type, edge_type>::GetEdge(int from, int to)
{
assert( (from < m_Nodes.size()) &&
(from >=0) &&
m_Nodes[from].Index() != invalid_node_index &&
"<SparseGraph::GetEdge>: invalid 'from' index");
assert( (to < m_Nodes.size()) &&
(to >=0) &&
m_Nodes[to].Index() != invalid_node_index &&
"<SparseGraph::GetEdge>: invalid 'to' index");
for (EdgeList::iterator curEdge = m_Edges[from].begin();
curEdge != m_Edges[from].end();
++curEdge)
{
if (curEdge->To() == to) return *curEdge;
}
assert (0 && "<SparseGraph::GetEdge>: edge does not exist");
}
//-------------------------- AddEdge ------------------------------------------
//
// Use this to add an edge to the graph. The method will ensure that the
// edge passed as a parameter is valid before adding it to the graph. If the
// graph is a digraph then a similar edge connecting the nodes in the opposite
// direction will be automatically added.
//-----------------------------------------------------------------------------
template <class node_type, class edge_type>
void SparseGraph<node_type, edge_type>::AddEdge(EdgeType edge)
{
//first make sure the from and to nodes exist within the graph
assert( (edge.From() < m_iNextNodeIndex) && (edge.To() < m_iNextNodeIndex) &&
"<SparseGraph::AddEdge>: invalid node index");
//make sure both nodes are active before adding the edge
if ( (m_Nodes[edge.To()].Index() != invalid_node_index) &&
(m_Nodes[edge.From()].Index() != invalid_node_index))
{
//add the edge, first making sure it is unique
if (UniqueEdge(edge.From(), edge.To()))
{
m_Edges[edge.From()].push_back(edge);
}
//if the graph is undirected we must add another connection in the opposite
//direction
if (!m_bDigraph)
{
//check to make sure the edge is unique before adding
if (UniqueEdge(edge.To(), edge.From()))
{
EdgeType NewEdge = edge;
NewEdge.SetTo(edge.From());
NewEdge.SetFrom(edge.To());
m_Edges[edge.To()].push_back(NewEdge);
}
}
}
}
//----------------------------- RemoveEdge ---------------------------------
template <class node_type, class edge_type>
void SparseGraph<node_type, edge_type>::RemoveEdge(int from, int to)
{
assert ( (from < (int)m_Nodes.size()) && (to < (int)m_Nodes.size()) &&
"<SparseGraph::RemoveEdge>:invalid node index");
EdgeList::iterator curEdge;
if (!m_bDigraph)
{
for (curEdge = m_Edges[to].begin();
curEdge != m_Edges[to].end();
++curEdge)
{
if (curEdge->To() == from){curEdge = m_Edges[to].erase(curEdge);break;}
}
}
for (curEdge = m_Edges[from].begin();
curEdge != m_Edges[from].end();
++curEdge)
{
if (curEdge->To() == to){curEdge = m_Edges[from].erase(curEdge);break;}
}
}
//-------------------------- AddNode -------------------------------------
//
// Given a node this method first checks to see if the node has been added
// previously but is now innactive. If it is, it is reactivated.
//
// If the node has not been added previously, it is checked to make sure its
// index matches the next node index before being added to the graph
//------------------------------------------------------------------------
template <class node_type, class edge_type>
int SparseGraph<node_type, edge_type>::AddNode(node_type node)
{
if (node.Index() < (int)m_Nodes.size())
{
//make sure the client is not trying to add a node with the same ID as
//a currently active node
assert (m_Nodes[node.Index()].Index() == invalid_node_index &&
"<SparseGraph::AddNode>: Attempting to add a node with a duplicate ID");
m_Nodes[node.Index()] = node;
return m_iNextNodeIndex;
}
else
{
//make sure the new node has been indexed correctly
assert (node.Index() == m_iNextNodeIndex && "<SparseGraph::AddNode>:invalid index");
m_Nodes.push_back(node);
m_Edges.push_back(EdgeList());
return m_iNextNodeIndex++;
}
}
//----------------------- CullInvalidEdges ------------------------------------
//
// iterates through all the edges in the graph and removes any that point
// to an invalidated node
//-----------------------------------------------------------------------------
template <class node_type, class edge_type>
void SparseGraph<node_type, edge_type>::CullInvalidEdges()
{
for (EdgeListVector::iterator curEdgeList = m_Edges.begin(); curEdgeList != m_Edges.end(); ++curEdgeList)
{
for (EdgeList::iterator curEdge = (*curEdgeList).begin(); curEdge != (*curEdgeList).end(); ++curEdge)
{
if (m_Nodes[curEdge->To()].Index() == invalid_node_index ||
m_Nodes[curEdge->From()].Index() == invalid_node_index)
{
curEdge = (*curEdgeList).erase(curEdge);
}
}
}
}
//------------------------------- RemoveNode -----------------------------
//
// Removes a node from the graph and removes any links to neighbouring
// nodes
//------------------------------------------------------------------------
template <class node_type, class edge_type>
void SparseGraph<node_type, edge_type>::RemoveNode(int node)
{
assert(node < (int)m_Nodes.size() && "<SparseGraph::RemoveNode>: invalid node index");
//set this node's index to invalid_node_index
m_Nodes[node].SetIndex(invalid_node_index);
//if the graph is not directed remove all edges leading to this node and then
//clear the edges leading from the node
if (!m_bDigraph)
{
//visit each neighbour and erase any edges leading to this node
for (EdgeList::iterator curEdge = m_Edges[node].begin();
curEdge != m_Edges[node].end();
++curEdge)
{
for (EdgeList::iterator curE = m_Edges[curEdge->To()].begin();
curE != m_Edges[curEdge->To()].end();
++curE)
{
if (curE->To() == node)
{
curE = m_Edges[curEdge->To()].erase(curE);
break;
}
}
}
//finally, clear this node's edges
m_Edges[node].clear();
}
//if a digraph remove the edges the slow way
else
{
CullInvalidEdges();
}
}
//-------------------------- SetEdgeCost ---------------------------------
//
// Sets the cost of a specific edge
//------------------------------------------------------------------------
template <class node_type, class edge_type>
void SparseGraph<node_type, edge_type>::SetEdgeCost(int from, int to, double NewCost)
{
//make sure the nodes given are valid
assert( (from < m_Nodes.size()) && (to < m_Nodes.size()) &&
"<SparseGraph::SetEdgeCost>: invalid index");
//visit each neighbour and erase any edges leading to this node
for (EdgeList::iterator curEdge = m_Edges[from].begin();
curEdge != m_Edges[from].end();
++curEdge)
{
if (curEdge->To() == to)
{
curEdge->SetCost(NewCost);
break;
}
}
}
//-------------------------------- UniqueEdge ----------------------------
//
// returns true if the edge is not present in the graph. Used when adding
// edges to prevent duplication
//------------------------------------------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::UniqueEdge(int from, int to)const
{
for (EdgeList::const_iterator curEdge = m_Edges[from].begin();
curEdge != m_Edges[from].end();
++curEdge)
{
if (curEdge->To() == to)
{
return false;
}
}
return true;
}
//-------------------------------- Save ---------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::Save(const char* FileName)const
{
//open the file and make sure it's valid
std::ofstream out(FileName);
if (!out)
{
throw std::runtime_error("Cannot open file: " + std::string(FileName));
return false;
}
return Save(out);
}
//-------------------------------- Save ---------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::Save(std::ofstream& stream)const
{
//save the number of nodes
stream << m_Nodes.size() << std::endl;
//iterate through the graph nodes and save them
NodeVector::const_iterator curNode = m_Nodes.begin();
for (curNode; curNode!=m_Nodes.end(); ++curNode)
{
stream << *curNode;
}
//save the number of edges
stream << NumEdges() << std::endl;
//iterate through the edges and save them
for (int nodeIdx = 0; nodeIdx < m_Nodes.size(); ++nodeIdx)
{
for (EdgeList::const_iterator curEdge = m_Edges[nodeIdx].begin();
curEdge!=m_Edges[nodeIdx].end(); ++curEdge)
{
stream << *curEdge;
}
}
return true;
}
//------------------------------- Load ----------------------------------------
//-----------------------------------------------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::Load(const char* FileName)
{
//open file and make sure it's valid
std::ifstream in(FileName);
if (!in)
{
throw std::runtime_error("Cannot open file: " + std::string(FileName));
return false;
}
return Load(in);
}
//------------------------------- Load ----------------------------------------
//-----------------------------------------------------------------------------
template <class node_type, class edge_type>
bool SparseGraph<node_type, edge_type>::Load(std::ifstream& stream)
{
Clear();
//get the number of nodes and read them in
int NumNodes, NumEdges;
stream >> NumNodes;
for (int n=0; n<NumNodes; ++n)
{
NodeType NewNode(stream);
//when editing graphs it's possible to end up with a situation where some
//of the nodes have been invalidated (their id's set to invalid_node_index). Therefore
//when a node of index invalid_node_index is encountered, it must still be added.
if (NewNode.Index() != invalid_node_index)
{
AddNode(NewNode);
}
else
{
m_Nodes.push_back(NewNode);
//make sure an edgelist is added for each node
m_Edges.push_back(EdgeList());
++m_iNextNodeIndex;
}
}
//now add the edges
stream >> NumEdges;
for (int e=0; e<NumEdges; ++e)
{
EdgeType NextEdge(stream);
m_Edges[NextEdge.From()].push_back(NextEdge);
}
return true;
}
#endif