-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBSTs_1008148648.c
executable file
·570 lines (515 loc) · 18.8 KB
/
BSTs_1008148648.c
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
/*
CSC A48 - Assignment 2 - BSTs, Traversals, a tiny Sequencer
For this assignment you will be implementing a fully working
BST. The goal is for you to gain practice with one of the most
common and more useful data structures you can find.
The data we will store in the BST corresponds to musical notes
from a little song, and we have provided (in a separate .c
file) a very small implementation of a program to making
sounds from each of these musical notes.
** YOU DO NOT NEED TO look at that code
** Everything in 'NoteSynth.c' is provided
** just so you can listen to the data in your
** BST - but you do not need to look at it for
** this assignment, and you're not expected
** to learn or understand that code.
You can, however, learn from it if you're curious about how
sound can be synthesized. Don't spend time on that unless you
have completed everything else.
Read carefully the comments and descriptions in this starter
code, as they constitute the specification of what you need
to do to complete the assignment.
- Like A1, we will provide a test driver for you to test your
code. Also like A1, that test driver contains a subset of the
tests we will be running. You are responsible for running
additional tests to ensure your BST works properly!
Updated Feb. 2022 (c) F. Estrada
*/
#include<stdio.h>
#include<stdlib.h>
#include"NoteSynth.c"
typedef struct BST_Node_Struct
{
// This compound type stores all data for one node of the
// BST. Since the BST is used to store musical notes,
// the data contained here represents one note from a
// musical score:
// freq: A double-precision floating point value,
// corresponding to the frequency (pitch) of the note
// bar: Musical scores are divided into 'bars' (which you can
// see are actually separated by a vertical bar!). This
// value indicates which bar the note happens in. The
// first bar in the musical score is 0
// index: Position of the note within the bar, from 0 (at the
// beginning of the bar) to 1 (at the end of the bar)
// key: A unique identifier (remember we discussed BST nodes
// should have unique keys to identify each node). We
// want our nodes to store notes in the order in which
// they occur in the song. So, the key identifier is
// created as: key = (10.0*bar)+index
// NOTE: This means only one note can have a specific
// bar,index value. If two notes should happen
// at the same time in the song, we make the
// index of one of them a tiny bit bigger or
// a tiny bit smaller than the other one so
// their keys are very close, but not identical.
double key;
double freq;
int bar;
double index;
/*** TO DO:
* Complete the definition of the BST_Node_Struct
***/
struct BST_Node_Struct *left;
struct BST_Node_Struct *right;
} BST_Node;
BST_Node *newBST_Node(double freq, int bar, double index)
{
/*
* This function creates and initializes a new BST_Node
* for a note with the given position (bar:index) and
* the specified frequency. The key value for the node
* is computed here as
*
* (10.0*bar)+index
*/
/*** TO DO:
* Complete this function to allocate and initialize a
* new BST_Node. You should make sure the function sets
* initial values for the data correctly.
****/
BST_Node *new_node=NULL;
new_node = (BST_Node *)calloc(1, sizeof(BST_Node));
new_node->bar=bar;
new_node->freq=freq;
new_node->index=index;
new_node->key= (10.0*bar)+index;
new_node->left=NULL;
new_node->right=NULL;
return new_node;
}
BST_Node *BST_insert(BST_Node *root, BST_Node *new_node)
{
/*
* This function inserts a new node into the BST. The
* node must already have been initialized with valid
* note data, and must have its unique key.
*
* The insert function must check that no other node
* exists in the BST with the same key. If a node with
* the same key exists, it must print out a message
* using the following format string
*
* printf("Duplicate node requested (bar:index)=%d,%lf, it was ignored\n",....);
* (of course you need to provide the relevant variables to print)
*
* And it must return without inserting anyting in the
* BST.
*/
/*** TO DO:
* Implement the insert function so we can add notes to the tree!
****/
// if tree is empty, return new node
if (root == NULL){
return new_node;
}
// check for duplicates
if (new_node->key==root->key){
printf("Duplicate node requested (bar:index)=%d,%lf, it was ignored\n",root->bar, root->index);
return root;
}
else if (new_node->key<root->key){
root->left= BST_insert(root->left, new_node);
}
else{
root->right=BST_insert(root->right, new_node);
}
return root;
}
BST_Node *BST_search(BST_Node *root, int bar, double index)
{
/*
* This function searches the BST for a note at the
* specified position. If found, it must return a
* pointer to the node that contains it.
* Search has to happen according to the BST search
* process - so you need to figure out what value to
* use during the search process to decide which branch
* of the tree to search next.
*/
/*** TO DO:
* Implement this function
****/
if (root==NULL) return NULL;
double key;
key = (10.0*bar)+index;
if (root->key == key){
return root;
}
if (key<root->key){
return BST_search(root->left, bar, index);
}
else{
return BST_search(root->right, bar, index);
}
return NULL;
}
BST_Node *find_successor(BST_Node *right_child_node)
{
/*
* This function finds the successor of a node by
* searching the right subtree for the node that
* is most to the left (that will be the node
* with the smallest key in that subtree)
*/
/*** TO DO:
* Implement this function
****/
//if successor is at the input node
if (right_child_node->left==NULL && right_child_node->right==NULL){
return right_child_node;
}
if (right_child_node->left !=NULL){
return find_successor(right_child_node->left);
}
return right_child_node;
}
BST_Node *BST_delete(BST_Node *root, int bar, double index)
{
/*
* Deletes from the BST a note at the specified position.
* You must implement the three cases of BST deletion
* we discussed in class. Make sure the function can
* remove a note at any position without breaking the
* tree!
*/
/*** TO DO:
* Implement this function
****/
BST_Node *temp;
double key;
key = (10.0*bar)+index;
if (root==NULL) return NULL;
else if (key<root->key){
root->left = BST_delete(root->left, bar, index);
}
else if (key>root->key){
root->right = BST_delete(root->right, bar, index);
}
else
{
//case a: no children
if (root->left==NULL && root->right==NULL){
free(root);
return NULL;
}
//case b: one child, left
else if (root->right==NULL){
temp=root->left;
free(root);
return temp;
}
//case b: one child, right
else if (root->left==NULL){
temp=root->right;
free(root);
return temp;
}
//case c
else{
temp=find_successor(root->right);
//copy from suc to root
root->key=temp->key;
root->index=temp->index;
root->freq=temp->freq;
root->bar=temp->bar;
//delete the chosen suc
root->right= BST_delete(root->right, temp->bar, temp->index);
}
}
return root;
}
void BST_makePlayList(BST_Node *root)
{
/*
* This function does an in-order traversal of the BST to
* generate an ordered list of notes to be played. Each
* note is added to a linked-list (already implemented,
* you only need to call the insert function) and the
* play list is then playable using the code in NoteSynth.c
*
* To insert a note, you need to call the function provided
* in NoteSynth.c:
*
* playlist_head=playlist_insert(playlist_head,freq,bar,index);
*
* playlist_head is a GLOBAL variable declared in NoteSynth.c
* precisely for this purpose. Don't worry about initializing
* it. It's set to NULL.
*
* playlist_insert() takes the frequency, bar, and index, and
* adds the note to the the *end* of the list - so notes
* have to be added in order - hence the in-order traversal
* this function has to do.
*/
/**** TO DO:
* Implement this function
****/
if (root == NULL) return;
BST_makePlayList(root->left);
playlist_head=playlist_insert(playlist_head,root->freq,root->bar,root->index);
BST_makePlayList(root->right);
}
void BST_inOrder(BST_Node *root, int depth)
{
/*
* This function performs an in-order traversal of the BST
* and prints out the note information for each note
* using this print statement:
*
* printf("Depth=%d, Bar:Index (%d:%f), F=%f Hz\n",...);
*
* Obviously, you must provide the bar, index, and frequency
* of the note that needs to be printed to complete the
* statement - we're just giving you the formatting string.
*
* The depth value is increased by 1 for each recursive call
* so when you print, you can see at what level each node
* is located! (this should help you debug your code by
* making it easier to check the shape of your BST).
*/
/*** TO DO:
* Implement this function
****/
if (root==NULL) return;
BST_inOrder(root->left, depth +1);
printf("Depth=%d, Bar:Index (%d:%f), F=%f Hz\n", depth, root->bar, root->index, root->freq);
BST_inOrder(root->right, depth+1);
}
void BST_preOrder(BST_Node *root, int depth)
{
/*
* This function performs an pre-order traversal of the BST
* and prints out the note information for each note
* using this print statement:
*
* printf("Depth=%d, Bar:Index (%d:%f), F=%f Hz\n",...);
*
* Obviously, you must provide the bar, index, and frequency
* of the note that needs to be printed to complete the
* statement - we're just giving you the formatting string.
*
* The depth value is increased by 1 for each recursive call
* so when you print, you can see at what level each node
* is located! (this should help you debug your code by
* making it easier to check the shape of your BST).
*/
/*** TO DO:
* Implement this function
****/
if (root==NULL) return;
printf("Depth=%d, Bar:Index (%d:%f), F=%f Hz\n", depth, root->bar, root->index, root->freq);
BST_preOrder(root->left, depth+1);
BST_preOrder(root->right, depth+1);
}
void BST_postOrder(BST_Node *root,int depth)
{
/*
* This function performs an post-order traversal of the BST
* and prints out the note information for each note
* using this print statement:
*
* printf("Depth=%d, Bar:Index (%d:%f), F=%f Hz\n",...);
*
* Obviously, you must provide the bar, index, and frequency
* of the note that needs to be printed to complete the
* statement - we're just giving you the formatting string.
*
* The depth value is increased by 1 for each recursive call
* so when you print, you can see at what level each node
* is located! (this should help you debug your code by
* making it easier to check the shape of your BST).
*/
/*** TO DO:
* Implement this function
****/
if (root==NULL) return;
BST_postOrder(root->left, depth+1);
BST_postOrder(root->right, depth+1);
printf("Depth=%d, Bar:Index (%d:%f), F=%f Hz\n", depth, root->bar, root->index, root->freq);
}
void delete_BST(BST_Node *root)
{
/*
* This function deletes the BST and frees all memory used for
* nodes in it. Recall that there is a specific order in which
* this needs to be done! (consult the Unit 4 notes as needed)
*/
/**** TO DO:
* Implement this function
****/
if (root==NULL) return;
delete_BST(root->left);
delete_BST(root->right);
free(root);
}
//helper function for reverse song used to go in the opposite direction as inorder
void deorder(BST_Node *root, double freq, int bar, double index, double key){
if (root==NULL) return;
deorder(root->right, root->freq, root->bar, root->index, root->key);
root->freq = freq;
root->bar = bar;
root->index = index;
root->key=key;
deorder(root->left, root->freq, root->bar, root->index, root->key);
}
BST_Node *reverseSong(BST_Node *root)
{
/*
* This function will reverse the song currently stored in our
* tree - that means the song will play *backwards*.
*
* For instance, if the song contains notes
*
* A B C D E F G in that order
*
* after reversing it should play
*
* G F E D C B A in that order
*
* In terms of the bar and index of each note in the input tree,
* here are some pieces of information you will need to figure
* out what the new bar and index of each note will be:
*
* If the maximum bar for a note in the input tree is MAX_BAR
* and the minimum (smallest) bar for a note in the input tree
* is MIN_BAR
*
* A note with bar=MIN_BAR will end up with bar=MAX_BAR
* A note with bar=MAX_BAR will end up with bar=MIN_BAR
*
* The index for any note must be between 0 and 1. If the
* original note had index=0, it will end up with index=1
* if the original note had index=1, it will end up with index=0
*
* That's all the information you need to figure out how to
* generate the notes for the backwards version of the song.
*
* It's up to you how to modify the tree so that the resulting
* song plays backwards. *There's many different ways to do this*
* As ever, I recommend you solve this first *on paper* and
* only start coding once you know what you have to do to solve this
* part.
*
*/
/*** TO DO:
* Implement this function! (Crunchy!)
****/
if (root==NULL) return NULL;
reverseSong(root->left);
deorder(root, root->freq, root->bar, 1 - root->index, (10.0*root->bar)+(1 - root->index));
reverseSong(root->right);
return root;
}
/********************************************************************************************
* Add any helper functions you need for implementing BST_harmonize() just below this
* comment block, and above BST_Harmonize itself!
* ******************************************************************************************/
int findfreqindex(double freq){
for (int j=0; j<100; j++){
if (note_freq[j]==freq){
return j;
}
}
return -1;
}
BST_Node *BST_harmonize(BST_Node *root, int semitones, double time_shift)
{
/* Let's play with notes, because we can.
*
* This function traverses the BST, and for each existing
* note, inserts a new, modified note (i.e. it will add sounds
* to an already existing song, based on the notes it already has)
*
* The new note has the following properties:
* - The frequency is shifted by the specified number of semitones
* (A semitone is the difference between one note and the
* immediately next one in the musical scale - ot what is the
* same, the difference in pitch between a white key and the
* black key immediately next to it in a piano)
* - It plays in the same *bar* as the original note
* - But its *index* is shifted by the specified time_shift
* (this value is between 0 and 1, but you have to check
* that the final index remains between 0 and 1)
*
* Both the 'semitones' and 'time_shift' parameter can be
* positive or negative. A typical value for semitones
* could be 4 or 7, corresponding to musical 3rds or
* musical 5ths - this should produce some interesting
* harmony! but you can play with this function and try
* various things for fun.
*
* In practice, figuring out the frequency of the note
* you have to insert is easy. For instance, suppose
* you have an existing note in the BST with
*
* freq=440.0, at bar=10, index=.25
*
* Now suppose the user specified
*
* semitones=4
* time_shift=.1
*
* Then you go to the note_freq[] array, find the index
* of the entry for frequency 440.0 (let's say it's
* j), then go to note_freq[j+4] to find the frequency
* of the note you need to add.
*
* NOTE: If the value of j+semitones is < 0 or > 99
* then there is no note with the frequency you
* want. In that case you don't insert a new
* note.
*
* You then add a new note with that frequency at
* bar=10 (same bar!)
* index=.25 + .1 (the original index plus the time_shift)
*
* NOTE: If the resulting index is less than 0, or >= 1,
* then you DO NOT insert the new note.
*
* This function is crunchy - and if you don't think it
* through before you start implementing it you'll run into
* all kinds of trouble.
*
* This is the problem solving exercise for A2, so don't
* look for people on Piazza to give you answers, or tell you
* what to do, or verify you're doing the right thing.
*
* It's up to you how to solve this, and if you want an opinion,
* you can come to visit us during office hours!
*
* Expected result: The BST will have about twice as many notes
* as before, and the new notes are shifted in pitch and
* in time as specified by the parameters.
*/
/*** TO DO:
* Implement this function
****/
int j=0;
BST_Node *new_node = NULL;
if (root !=NULL) {
// copy bst into new bst
root->left = BST_harmonize(root->left, semitones, time_shift);
root->right = BST_harmonize(root->right, semitones, time_shift);
j= findfreqindex(root->freq);
if ((j!=-1) && (j+semitones>=0) && (j+semitones<100))
{
if ((root->index + time_shift>=0) &&(root->index+time_shift<1))
{
new_node = newBST_Node(note_freq[j+semitones], root->bar, root->index+time_shift);
root = BST_insert(root, new_node);
}
}
}
return root;
}