1 Basic Test Results 2 Readme 3 Statement - PDF 4 Spreaderdetectorbackend.C
1 Basic Test Results 2 Readme 3 Statement - PDF 4 Spreaderdetectorbackend.C
2 README 4
3 STATEMENT.pdf 5
4 SpreaderDetectorBackend.c 6
1
1 Basic Test Results
1 ********************************************
2 * *
3 * Hello dear C&C++ Workshop Student, *
4 * We wish you good luck on your exam! *
5 * *
6 ********************************************
7 Running...
8
9 Opening tar file
10 OK
11 Tar extracted O.K.
12
13 Checking files...
14 OK
15 Making sure files are not empty...
16 OK
17 Compilation check...
18
19 Compiling...
20 OK
21
22 **********************************
23 * *
24 * Compilation seems OK! *
25 * Check if you got warnings! *
26 * *
27 **********************************
28
29 =====================
30 Public test cases
31 =====================
32
33 =====================
34 Running SpreaderDetector - Test # 1
35 OK
36 Running diff
37 OK
38 Test passed.
39 =====================
40
41 =====================
42 Running SpreaderDetector - Test # 2
43 OK
44 Running diff
45 OK
46 Test passed.
47 =====================
48
49 =====================
50 Running SpreaderDetector - Test # 3
51 OK
52 Running diff
53 OK
54 Test passed.
55 =====================
56
57 ***********************************
58 * *
59 * presubmission script passed *
2
60 * 3/3 tests passed *
61 * *
62 ***********************************
63
64 =========================
65 = Checking coding style =
66 =========================
67 ** Total Violated Rules : 0
68 ** Total Errors Occurs : 0
69 ** Total Violated Files Count: 0
3
2 README
1 Name: Ido Akov
2 ID: 302246111
3 CS-USER: ikavodo
4
5 SpreaderDetectorBackend
6 -----------------------------
7 Please explain how you dealt with the following parts of the exam.
8
9 Input processing
10 ----------------
11 I used fgets to process the lines in a file, if there are any.
12 I then used sscanf to format the line, and save the data via pointer to a dynamically-allocated
13 struct I called "Person".
14
15 Data storing
16 ------------
17 I saved all data to a binary search tree, based on id comparison. This is of complexity
18 O(mlogn) on average, and O(mn) in the worst case (if people in the file are sorted by id),
19 with n being the number of people for which we are inputting data into the tree, and m the
20 number of meetings.
21 We notice that there are no cycles in the graph,meaning m <= n-1 = O(n), thus we get a final
22 average complexity of O(nlogn), and worst time of O(n^2).
23 The binary search tree also allowed me to read through the files only once, because working with
24 pointers means not having to constantly change allocated memory or check the file size at first.
25
26 Results sorting
27 ---------------
28 I copied the Binary search tree data to a dynamically allocated array of pointers, and then used
29 the built-in qsort function to sort the pointers by the probability of infection data in the
30 struct to which they point.
31 Copying the tree is of complexity O(n), and sorting is of complexity O(nlogn) on average, and in
32 the worst case O(n^2).
33 Thus we get a final run time of O(nlogn) on average for the program, O(n^2) in the worst
34 possible case.
35
36
37
4
אני מצהיר/ה בזאת כי ידוע לי שאם יתגלה כי עברתי עבירת העתקה מסוג זה,
תוגש נגדי תלונה על כך לוועדת המשמעת של האוניברסיטה העברית.
6
60 } BST;
61
62 //function declarations (see implementations for documentation)
63 BST *readPersonsFile(FILE *persons, FILE *meetings);
64
65 Node *makeNode(const char name[LINE_LENGTH], const unsigned long id, const float age);
66
67 void freeTree(BST **tree);
68
69 void freeAllNodes(Node *pNode);
70
71 void freeNode(Node *pNode);
72
73 void insertNodeToTree(BST *pBst, Node *pNode);
74
75 int idCompare(const unsigned long id1, const unsigned long id2);
76
77 void readMeetingsFile(const BST *pTree, FILE *meetings);
78
79 int writeFile(BST *pTree, const char *p, Person **pArray, const unsigned int arrLength);
80
81 int stdError(FILE *persons, FILE *meetings);
82
83 Node *findNode(const BST *pBst, const unsigned long id);
84
85 float crna(const float d, const float time);
86
87 void copyTreeToArray(const Node *pNode, Person **pPerson);
88
89 BST *initializeNewBST();
90
91 /**
92 * function returns informative message to the user about an error and aborts the program
93 * @param err informative message
94 * @return code 1
95 */
96 int error(const char *err)
97 {
98 fprintf(stderr, "%s", err);
99 return EXIT_FAILURE;
100 }
101
102 /**
103 * comparator function for sorting persons by infectionRate
104 * @param a pointer to first Person
105 * @param b pointer to second Person
106 * @return 0 if equal, -1 if first is greater (for descending order), else 1
107 */
108 int compareByInfectionRate(const void *a, const void *b)
109 {
110 Person *A = (*(Person **) a);
111 Person *B = (*(Person **) b);
112 return A->infectionRate > B->infectionRate ? SMALLER : A->infectionRate <
113 B->infectionRate ? GREATER : 0;
114 }
115
116 /**
117 * main program - process files, save data to a binary search tree, calculate each Person's
118 * probable likelihood of infection, sort by likelihood and save analysis to new file
119 * @param argc number of arguments to program
120 * @param argv arguments
121 * @return success or failure
122 */
123 int main(int argc, char *argv[])
124 {
125 if (argc != ARGS_NUM)
126 {
127 //wrong number of inputs
7
128 return error(USAGE);
129 }
130 FILE *persons = fopen(argv[1], READ);
131 if (persons == NULL)
132 {
133 //persons file wasn't found
134 fclose(persons);
135 return error(INPUT_ERROR);
136 }
137 FILE *meetings = fopen(argv[2], READ);
138 if (meetings == NULL)
139 {
140 //meetings file wasn't found
141 fclose(persons);
142 fclose(meetings);
143 return error(INPUT_ERROR);
144 }
145 //save data to binary search tree
146 BST *tree = readPersonsFile(persons, meetings);
147 fclose(persons);
148 if (tree == NULL)
149 {
150 //meetings file must also be empty because of program assumptions
151 fclose(meetings);
152 //return empty file
153 return writeFile(NULL, OUTPUT_FILE, NULL, 0);
154 }
155 //calculate infection likelihoods
156 readMeetingsFile(tree, meetings);
157 fclose(meetings);
158 Person **pArr = (Person **) malloc(sizeof(Person *) * tree->size);
159 if (pArr == NULL)
160 {
161 //in case of malloc failure free all allocated memory and exit
162 freeTree(&tree);
163 return stdError(persons, meetings);
164 }
165 //copy data to array for sorting
166 copyTreeToArray(tree->root, pArr);
167 //sort by infectionRate
168 qsort(pArr, tree->size, sizeof(Person *), compareByInfectionRate);
169 //write analysis to new file
170 return writeFile(tree, OUTPUT_FILE, pArr, tree->size);
171 }
172
173 /**
174 * copy all data from binary search tree to array for sorting by infectionRate
175 * @param pNode pointer to a node within the tree
176 * @param pPerson pointer to dynamically allocated-array
177 */
178 void copyTreeToArray(const Node *pNode, Person **pPerson)
179 {
180 if (!pNode)
181 {//reached NULL leaf
182 return;
183 }
184 //recursively call left and right children
185 copyTreeToArray(pNode->left, pPerson);
186 pPerson[ind] = pNode->data;
187 //keep track of indices
188 ind++;
189 copyTreeToArray(pNode->right, pPerson);
190 }
191
192 /**
193 * write analysis to new file
194 * @param pTree pointer to binary search tree
195 * @param path of new file
8
196 * @param pArray pointer to sorted array
197 * @param arrLength length of array
198 * @return success or failure
199 */
200 int writeFile(BST *pTree, const char *path, Person **pArray, const unsigned int arrLength)
201 {
202 FILE *analysis = fopen(path, WRITE);
203 if (analysis == NULL)
204 {
205 //error opening file
206 return error(OUTPUT_ERROR);
207 }
208 if (pTree == NULL)
209 {
210 //if Persons file was empty other files are already closed
211 fclose(analysis);
212 return EXIT_SUCCESS;
213 }
214 else
215 {
216 //neither tree nor array are empty
217 for (unsigned int i = 0; i < arrLength; i++)
218 {
219 Person *cur = pArray[i];
220 float val = cur->infectionRate;
221 //check infection factor of current person, print relevant message
222 const char *msg = val > MEDICAL_SUPERVISION_THRESHOLD ?
223 MEDICAL_SUPERVISION_THRESHOLD_MSG :
224 val > REGULAR_QUARANTINE_THRESHOLD ? REGULAR_QUARANTINE_MSG
225 : CLEAN_MSG;
226 fprintf(analysis, msg, cur->name, cur->id);
227 }
228 }
229 fclose(analysis);
230 //free allocated memory- data pointers first
231 freeTree(&pTree);
232 //finally pointer to dynamically-allocated array
233 free(pArray);
234 pArray = NULL;
235 return EXIT_SUCCESS;
236 }
237
238 /**
239 * parse file with data about meetings of carriers and potential carriers
240 * @param pTree pointer to binary search tree
241 * @param meetings pointer to file with data about meetings
242 */
243 void readMeetingsFile(const BST *pTree, FILE *meetings)
244 {
245 char line[LINE_LENGTH];
246 if (fgets(line, LINE_LENGTH, meetings))
247 {
248 //parse first line
249 unsigned long infector;
250 sscanf(line, "%lu", &infector);
251 Node *carrier = findNode(pTree, infector);
252 carrier->data->infectionRate = POSITIVE;
253 //set vars to hold data
254 unsigned long infected;
255 float dist;
256 float time;
257 while (fgets(line, LINE_LENGTH, meetings))
258 {
259 sscanf(line, "%lu %lu %f %f", &infector, &infected, &dist, &time);
260 if (idCompare(infector, carrier->data->id) != EQUAL)
261 //we are examining meetings with a different potential carrier
262 {
263 carrier = findNode(pTree, infector);
9
264 }
265 Node *exposed = findNode(pTree, infected);
266 //we know that the product of all previous encounters is equal to the infectionRate
267 //of the current potential carrier
268 exposed->data->infectionRate = carrier->data->infectionRate * crna(dist, time);
269 }
270 }
271 }
272
273 /**
274 * formula for the calculation of infectionRate of a potential carrier, with respect to time and
275 * distance in which they met a previous potential carrier
276 * @param dist distance
277 * @param time
278 * @return probability likelihood of a being a carrier
279 */
280 float crna(const float dist, const float time)
281 {
282 return (time * MIN_DISTANCE) / (dist * MAX_TIME);
283 }
284
285 /**
286 * find a node within the BST by id
287 * @param pBst pointer to binary search tree
288 * @param id to be found within tree
289 * @return relevant node
290 */
291 Node *findNode(const BST *pBst, const unsigned long id)
292 {
293 Node *p = pBst->root;
294 while (p)
295 {
296 //search for node with relevant data
297 int diff = idCompare(p->data->id, id);
298 if (diff == EQUAL)
299 {
300 //node with data was found
301 return p;
302 }
303 else
304 {
305 //if diff is smaller than equal check node's right child, otherwise check left child
306 p = (diff < EQUAL) ? p->right : p->left;
307 }
308 }
309 //this shouldn't happen because we assume every id in Meetings file exists in
310 //Persons file
311 return NULL;
312 }
313
314 /**
315 * parse Persons data file
316 * @param persons pointer to file
317 * @param meetings pointer to file with meetings data
318 * @return pointer to a binary search tree which holds all data
319 */
320 BST *readPersonsFile(FILE *persons, FILE *meetings)
321 {
322 BST *tree = NULL;
323 //parse all data in file line by line
324 char line[LINE_LENGTH];
325 unsigned long id;
326 float age;
327 char name[LINE_LENGTH];
328 while (fgets(line, LINE_LENGTH, persons))
329 {
330 if (tree == NULL)
331 {
10
332 //file isn't empty- create BST to process and store file data
333 tree = initializeNewBST();
334 if (tree == NULL)
335 {
336 //memory allocation failed
337 exit(stdError(persons, meetings));
338 }
339 }
340 sscanf(line, "%s %lu %f", name, &id, &age);
341 Node *cur = makeNode(name, id, age);
342 if (cur == NULL)
343 {
344 //problem creating a new node, free all allocated memory
345 freeTree(&tree);
346 exit(stdError(persons, meetings));
347 }
348 insertNodeToTree(tree, cur);
349 }
350 return tree;
351 }
352
353 /**
354 * make a new, empty binary search tree to hold data within
355 * @return pointer to the tree
356 */
357 BST *initializeNewBST()
358 {
359 BST *newTree = (BST *) malloc(sizeof(BST));
360 if (newTree == NULL)
361 {
362 //memory allocation failed
363 return NULL;
364 }
365 else
366 {
367 //initialize new BST, set default fields
368 newTree->root = NULL;
369 newTree->size = 0;
370 }
371 return newTree;
372 }
373
374 /**
375 * close all files in case of error, return informative message and code 1
376 * @param persons file
377 * @param meetings file
378 * @return failure
379 */
380 int stdError(FILE *persons, FILE *meetings)
381 {
382 fclose(persons);
383 fclose(meetings);
384 return error(STANDARD_LIB_ERR_MSG);
385 }
386
387 /**
388 * put new Node with data describing a potential corona carrier into the binary search tree
389 * @param pBst pointer to tree
390 * @param pNode pointer to node
391 */
392 void insertNodeToTree(BST *pBst, Node *pNode)
393 {
394 Node *p = pBst->root;
395 if (p == NULL)//tree is empty
396 {
397 pBst->root = pNode;
398 }
399 else
11
400 {
401 while (p)
402 //traverse tree to find insertion spot.
403 {
404 int diff = idCompare(p->data->id, pNode->data->id);
405 if (diff == GREATER)
406 {
407 //if current tree node is larger than new node
408 if (p->left == NULL)
409 {
410 //new node is the new predecessor to p
411 p->left = pNode;
412 break;
413 }
414 //compare left child to new node
415 p = p->left;
416 }
417 else
418 {
419 //new node is larger
420 if (p->right == NULL)
421 {
422 //new node is the new successor to p
423 p->right = pNode;
424 break;
425 }
426 //compare right child to new node
427 p = p->right;
428 }
429 }
430 }
431 pBst->size++;
432 }
433
434 /**
435 * comparator within binary search tree. Allows us to find a node by ID in O(logn) on average
436 * @param id1 first id
437 * @param id2 second id
438 * @return -1 if first is smaller, 1 if first is larger, otherwise 0
439 */
440 int idCompare(const unsigned long id1, const unsigned long id2)
441 {
442 return id1 < id2 ? SMALLER : id1 > id2 ? GREATER : EQUAL;
443 }
444
445 /**
446 * free all allocated memory within binary search tree
447 * @param tree pointer to pointer to the BST
448 */
449 void freeTree(BST **tree)
450 {
451 freeAllNodes((*tree)->root);
452 free(*tree);
453 *tree = NULL;
454 }
455
456 /**
457 * free all memory allocated within nodes for data
458 * @param pNode pointer to a node
459 */
460 void freeAllNodes(Node *pNode)
461 {
462 if (!pNode)
463 {
464 return;
465 }
466 //recursively free left and right children
467 freeAllNodes(pNode->left);
12
468 freeAllNodes(pNode->right);
469 freeNode(pNode);
470 }
471
472 /**
473 * free data within a node
474 * @param pNode pointer to node
475 */
476 void freeNode(Node *pNode)
477 {
478 free(pNode->data);
479 free(pNode);
480 }
481
482 /**
483 * make a new Node holding data about a corona carrier to add to the BST
484 * @param name of carrier
485 * @param id of carrier
486 * @param age of carrier
487 * @return pointer to new Node if successful
488 */
489 Node *makeNode(const char name[LINE_LENGTH], const unsigned long id, const float age)
490 {
491 Node *node = (Node *) malloc(sizeof(Node));
492 if (!node)
493 {
494 return NULL;
495 }
496 //initialize node to default values
497 node->right = node->left = NULL;
498 node->data = (Person *) malloc(sizeof(Person));
499 if (node->data == NULL)
500 {
501 //if memory allocation failed, free previous allocated memory
502 free(node);
503 return NULL;
504 }
505 node->data->age = age;
506 node->data->id = id;
507 strcpy(node->data->name, name);
508 node->data->infectionRate = 0.0f;
509 return node;
510 }
511
512
513
514
13