-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
512 lines (474 loc) · 13.2 KB
/
main.cpp
File metadata and controls
512 lines (474 loc) · 13.2 KB
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
/**
* Better Programming Practices
*
* Compilation of bad code from various sources
*
* This file will not compile, but it is indented properly! ;-)
*
* Index
*
* TODO -- NEED to PRIORITIZE by SEVERITY
* TODO -- add from http://faculty.washington.edu/pisan/cpp/snippets.html
*
* ERR: Cleanup your code
* ERR: 80 Characters
* ERR: Meaningful comments
* ERR: Destructor Destroys
* ERR: if (found == true)
* ERR: Return the bool
* ERR: cin skips
* ERR: const reference when possible
* ERR: Meaningful variable names
* ERR: Initialize in header OR in constructor
* ERR: Use initialization lists
* ERR: Trust the Compiler
* ERR: Empty Destructor
* ERR: Assert to Check
* ERR: return const reference
* ERR: if outside of for
* ERR: stringstream if lots of string appends
* ERR: TODO
* ERR: nullptr is false
* ERR: conditional operator
*/
/**
* ERR: Cleanup your code
* If it is unused, take it out
* Also you need a SPACE after //
*/
class Edge {
friend class Vertex;
friend class Graph;
public:
//Unused Getters and Setters
/*
int getWeight() const;
Vertex* getVertexTo() const;
Vertex* getVertexFrom() const;
*/
private:
//Initialize an edge with 2 vertex pointers and a edge weight
Edge(Vertex *vertexFrom, Vertex *vertexTo, int edgeWeight);
};
/**
* ERR: 80 Characters
* Is there a reson to go over 80 characters in this case?/
*/
Edge::Edge(Vertex *v1, Vertex *v2, int edgeWeight) : vFrom(v1), vTo(v2), weight(edgeWeight) {}
/**
* ERR: Meaningful comments
*
* If your code is so close to English or any rasonable C++ speaker
* can see what you are doing, do not document it
* Refactor/rename variables instead
* Below "delete e" could be "delete edge"
* Look we got self documenting code
* Each function needs a comment, but inline comments only when something
* tricky is going on, not for what can be read in English
*/
/** destructor, delete all vertices and edges */
Graph::~Graph() {
//Iterate through all vertices and all edges in the vertices
for (auto const &v : vertices) {
for (auto const &e : v.second->allOutgoingEdges) {
//Delete the edge
delete e;
}
//Delete the vertex
delete v.second;
}
}
/**
* ERR: Destructor Destroys
*
* Does std::map.clear() destroy anything?
* Does setting an integer to 0 destroy anything?
* Assuming myEdgesPtr is private and nobody can access it after the destructor
* is called, what is the point of setting it?
*/
Graph::~Graph() {
//Clear the map
vertices.clear();
edges = 0;
myEdgesPtr = nullptr;
}
/**
* ERR: if (found == true)
*
* Do we have to check if a bool is true as a condition?
* bool is already a true/false value
* Use if (found) or maybe
* use if(!found)
* Doesn't that read better?
*/
bool Graph::Connect(const string &fromLabel,
const string &toLabel, int edgeWeight = 0) {
//If vertices don't exist, add them
if (HasVertex(fromLabel) == false) {
AddVertex(fromLabel);
}
}
/**
* ERR: Return the bool
*
* If a function is already returning a bool, you can return that value
* No need to use if(funcReturnsTrue) return true else resturn false
* return funcReturnsTrue;
* It also works to return the opposite truth value
* return !findEdge(otherVertex);
*/
bool Vertex::addEdge(Vertex &otherVertex, int weight) {
// code deleted
if (findEdge(otherVertex))
return true;
return false;
}
bool Vertex::removeEdge(Vertex &otherVertex) {
// code deleted
if (!(findEdge(otherVertex)))
return true;
return false;
}
/**
* ERR: cin skips
*
* The format of the data file is an integer for number-of-edges
* followed by that many "string string int" lines
* Instead of reading the first integer and then using a for loop,
* the code below discards the number-of-edges
* Each iteration of the loop calls getline,
* which has nothing to read but a newline
*
* cin and ifstream will read the correct data types,
* so would have already skipped over newline and extra spaces
* No need for getline
* Plus, if we put additional comments below the graph info
* now the graph function will error out
*/
bool Graph::ReadFile(const string &filename) {
int edgeWeight;
string line, vertexFrom, vertexTo;
ifstream file(filename);
if (file.is_open()) {
while (getline(file, line)) {
file >> vertexFrom >> vertexTo >> edgeWeight;
// Connect(vertexFrom, vertexTo, edgeWeight);
}
}
}
/**
* ERR: const reference when possible
*
* If it is not a builtin data type (bool, char, int, double, float),
* do not copy unless you really really need to
*/
Vertex::Vertex(string l) : label(l), visited(false) {}
/**
* ERR: Meaningful variable names
*
* label instead of l
* l is especially bad since it looks like the number "1" for certain fonts
*/
Vertex::Vertex(string l) : label(l), visited(false) {}
/**
* ERR: Initialize in header OR in constructor
*
* Decide where you want to initialize your variables and srtick to it
* It is OK to initialize some in header and some in constructor, but
* you should not have both.
* Leads to confusion when defaults change.
*/
Vertex::Vertex(string l) : label(l), visited(false) {}
// in .h file
// bool visited = false;
// string label = "";
/**
* ERR: Use initialization lists
*
* When possible use initialization lists rather than initializing
* variables in the body of the constructor
*/
Vertex::Vertex() {
vertexLabel = "";
visited = false;
}
/**
* ERR: Trust the Compiler
*
* Make the compiler generate the default empty constructor
* You can use
* Vertex() = default;
* in .h file and set default values in .h file
*/
Vertex::Vertex() {
vertexLabel = "";
visited = false;
}
/**
* ERR: Empty Destructor
*
* Unless you have a virtual function, do not write an empty destructor
* Eat-my-words: I previously suggested writing empty destructuctor
* even when it is empty as a good habit. Proabbly a good idea when starting
* programmers, but concise code is better for more advanced programmers
*/
Vertex::~Vertex() {
}
/**
* ERR: Assert to Check
*
* Use assert to check that functions are working correctly
* Assuming removeEdgeHelper is working correctly, this function should
* always return true if the edge is deleted, so check it with
* assert(!findEdge(otherVertex))
* assert statements can be excluded from release code, so your code will
* run faster in release version, but still be fully testable as you work
*/
bool Vertex::removeEdge(Vertex &otherVertex) {
if (!findEdge(otherVertex))
return false;
Edge *toBeDeleted = removeEdgeHelper(otherVertex);
delete toBeDeleted;
// confirm disconnected
return !findEdge(otherVertex);
}
/**
* ERR: return const reference
*
* Better to return const reference to provide a reference to the object
* without letting the caller modify it
* const string& string Vertex::getLabel() const;
* Returning a reference means, the caller can either use
* const string &label = v.getLabel()
* OR
* string label = v.getLabel()
* if they want their own copy. Their choice!
*/
string Vertex::getLabel() const {
return vertexLabel;
}
/**
* ERR: if outside of for
*
* The code below is trying to print edges with commas between them
* something like "A-B 5, A-F 3, A-H 2" without having a comma at the end
* Having an if statement inside the loop means, it checks the condition
* for each iteration. If there are million edges, it checks it million
* times when we only need to check it once using
* string Vertex::print() const {
* string vertexString = "";
* if (edges.size() > 0)
* vertexString += edges[0]->print();
* for (size_t i = 1; i < edges.size(); i++) {
* vertexString += ",";
* vertexString += edges[i]->print();
* }
* return vertexString;
* }
*/
string Vertex::print() const {
string vertexString = "";
for (size_t i = 0; i < edges.size(); i++) {
vertexString += edges[i]->print();
if (i < edges.size() - 1)
vertexString += ",";
}
return vertexString;
}
/**
* ERR: stringstream if lots of string appends
*
* If you are putting lots of things into a string, use a stringstream
* rather than using + or append
* #include <sstream>
* string Vertex::print() const {
* stringstream ss;
* if (edges.size() > 0)
* ss << edges[0]->print();
* for (size_t i = 1; i < edges.size(); i++)
* ss << "," << edges[i]->print();
* return ss.str();
* }
*/
string Vertex::print() const {
string vertexString = "";
for (size_t i = 0; i < edges.size(); i++) {
vertexString += edges[i]->print();
if (i < edges.size() - 1)
vertexString += ",";
}
return vertexString;
}
/**
* ERR: TODO
*
* Add TODO for function stubs that you will implement later
* AND, implement them before submitting
* You can search for TODO in the whole project before final submission
*/
// destructor, delete all vertices and edges
Graph::~Graph() {
}
/**
* ERR: nullptr is false
*
* nullptr will be cast to the boolean false, much cleaner to write
* if (v) ... else ...;
* This works because there is an implicit conversion from pointer to bool
* (i.e. a constructor for bool that is not marked explicit and takes a pointer)
*/
int Graph::NumberOfEdges(const string &label) const {
Vertex *v = findVertex(label);
if (v != nullptr)
return v->numberOfEdges();
// if Vertex was not found - nullptr - then return -1
return -1;
}
/**
* ERR: conditional operator
*
* Do not abuse the "?" conditional operator, but use it to simplify code
* Vertex *v = findVertex(label);
* return v ? v->numberOfEdges() : -1;
*/
int Graph::NumberOfEdges(const string &label) const {
Vertex *v = findVertex(label);
if (v != nullptr)
return v->numberOfEdges();
// if Vertex was not found - nullptr - then return -1
return -1;
}
* ERR:
cin skips
/**
* ERR: compact cin
*
* cin and ifstream will extract multiple variables per line
* file >> vFrom >> vTo >> weight;
*/
bool Graph::ReadFile(const string &filename) {
// code deleted
// read rest of lines (numberOfEdges times)
for (int i = 0; i < numberOfEdges; i++) {
file >> vFrom;
file >> vTo;
file >> weight;
Connect(vFrom, vTo, weight);
}
}
/**
* ERR: similar names, similar functions
*
* if getEdges returns a string and Vertex::print returns a string
* why do they have such different names?
* For that matter, GetEdges should really return edges, i.e edge objects
* If we want a string, we should have GetEdgesAsString
*/
string Graph::GetEdges(const string &label) const {
return findVertex(label)->print();
}
string Vertex::print() const {
string vertexString = "";
// code deleted
return vertexString;
}
/**
* ERR: explicit constructors
*
* if a constructor takes a single parameter,
* make it explicit otherwise it cannot be explicit
*/
class Vertex {
friend class Graph;
private:
// Declaration of Vertex class' one-parameter constructor
// Initializes Vertex with string vertexLabel
Vertex(const string &vertexLabel);
explicit Vertex(const string &vertexLabel, bool visited);
};
/**
* ERR: static functions
*
* if a class function does not need to access the object,
* make it static
*/
class Vertex {
private:
bool compareEdge(Edge *firstEdge, Edge *secondEdge);
};
/**
* ERR: range-based-for
*
* Use range based for over index based for or over iterators
* for (auto& edge : edgesGoingOut)
* delete edge
*/
Vertex::~Vertex() {
for (std::vector<Edge *>::iterator it = edgesGoingOut.begin();
it != edgesGoingOut.end(); ++it)
delete *it;
edgesGoingOut.clear();
}
/**
* ERR: const getters
*
* getter should be const functions
* other functions should also be const whenever possible
* Sometimes it is necessary to write two versions of the same function
* one as const, and the other non-const. This is standard practice.
*/
class Vertex {
public:
Vertex();
string getLabel() { return label; }
};
/**
* ERR: simplify conditions
*
* combne if statements if the body is the same
* if ((edge->getVertex1Pointer() == vertex) ||
* (edge->getVertex2Pointer() == vertex))
* return true;
*/
bool Vertex::isConnectedTo(Vertex *vertex) {
for (Edge *edge: edges) {
if (edge->getVertex1Pointer() == vertex)
return true;
if (edge->getVertex2Pointer() == vertex)
return true;
}
return false;
}
/**
* ERR: extra vectors
*
* beware of making extra copies of vector objects,
* return by const reference if possible,
* const vector<Edge *>& Vertex::getEdges()
* return by reference if not
* vector<Edge *>& Vertex::getEdges()
* This case is relatively harmless since it is a vector of pointers,
* which are just integers, but still....
*/
vector<Edge *> Vertex::getEdges() {
return edges;
}
/**
* ERR: map key exists
*
* use container.count(key) == 1 to check if the key exists in the map
* if you use container[key] then you are forcing the map to create that key
* with the default values, increasing the size of the map unnecessarily
* and possibly creating a new object using the default constructor
* Testcase:
* class Foo {};
* map<int, Foo*> mp;
* cout << "size: " << mp.size() << endl;
* if (mp[3] == nullptr);
* cout << "size: " << mp.size() << endl;
*/
Vertex *Graph::createVertex(const std::string &vertexLabel) {
if (vertices[vertexLabel] == nullptr) {
// ...
}
}