Compare commits

..

41 Commits

Author SHA1 Message Date
48d8b8fcfd add solution for lab07 2025-03-26 13:01:42 -04:00
Jidong Xiao
eaa3021d47 restore color after updating 2025-03-26 13:01:42 -04:00
Jidong Xiao
8e9b9675bf actually we need to let 7 take over 5 2025-03-26 13:01:42 -04:00
Jidong Xiao
cc162dff6f need to hide 7.5 2025-03-26 13:01:42 -04:00
Jidong Xiao
09745ed253 don't move 7.5, just update 5 2025-03-26 13:01:42 -04:00
Jidong Xiao
7750b9bba2 don't move 7.5, just update 5 2025-03-26 13:01:42 -04:00
Jidong Xiao
1e9e14e83c adding the missing bracket 2025-03-26 13:01:42 -04:00
Jidong Xiao
73b283c87f split into 3 steps 2025-03-26 13:01:42 -04:00
Jidong Xiao
981bb8394b support deleting 5 2025-03-26 13:01:42 -04:00
Jidong Xiao
f8f4250479 move 7 and 7.5 if deleting 8 2025-03-26 13:01:42 -04:00
Jidong Xiao
dafa3d68e8 now it's moving 7.5, not 8 2025-03-26 13:01:42 -04:00
Jidong Xiao
1dd3a91c3c move 7 and 8 2025-03-26 13:01:42 -04:00
Jidong Xiao
68bdc8d087 move 7 and 8 2025-03-26 13:01:42 -04:00
Jidong Xiao
7443ce2e1a hide bad words 2025-03-26 13:01:42 -04:00
Jidong Xiao
4b1246b9a1 hide the bad words 2025-03-26 13:01:42 -04:00
Jidong Xiao
12bbbf410f hide the bad words 2025-03-26 13:01:42 -04:00
Jidong Xiao
3917bbbdc1 add them back 2025-03-26 13:01:42 -04:00
Jidong Xiao
ec5739add4 10 to 8 2025-03-26 13:01:42 -04:00
Jidong Xiao
e783fa7d83 remove some useless comments 2025-03-26 13:01:42 -04:00
Jidong Xiao
1556940408 completing erase 2025-03-26 13:01:42 -04:00
Jidong Xiao
eb67680841 dirent not allowed in the future 2025-03-26 13:01:42 -04:00
Jidong Xiao
a845f0752c dirent not allowed in the future 2025-03-26 13:01:42 -04:00
Jidong Xiao
610455146e now bfs using queues 2025-03-26 13:01:42 -04:00
Jidong Xiao
e005a62828 adding level order animation 2025-03-26 13:01:42 -04:00
Jidong Xiao
ba74c7efbe line break 2025-03-26 13:01:42 -04:00
Jidong Xiao
6198e34b84 adding animation 2025-03-26 13:01:42 -04:00
Jidong Xiao
c57da3131c approach 2 moved to lec 20 2025-03-26 13:01:42 -04:00
Jidong Xiao
d833d16444 moving image to lecture 20 2025-03-26 13:01:42 -04:00
Jidong Xiao
d6e4a2cfae adding the ptrs implementation of iterator incrementing 2025-03-26 13:01:41 -04:00
Jidong Xiao
c9d4888ed6 remove auto 2025-03-26 13:01:41 -04:00
Jidong Xiao
9feed1f407 mentioning the destructor 2025-03-26 13:01:41 -04:00
Jidong Xiao
be8d649ead include links to set implementation' 2025-03-26 13:01:41 -04:00
Jidong Xiao
230751b5b8 renaming 2025-03-26 13:01:41 -04:00
Jidong Xiao
a9ced246db adding the almost completed ds set 2025-03-26 13:01:41 -04:00
Jidong Xiao
956d3892da create set main and ds set main 2025-03-26 13:01:41 -04:00
Jidong Xiao
fb81b68821 commenting out B+ trees 2025-03-26 13:01:41 -04:00
Jidong Xiao
640cfc6c08 adding a general tree example png file 2025-03-26 13:01:41 -04:00
Jidong Xiao
97034d0b94 adding a general tree example 2025-03-26 13:01:41 -04:00
Jidong Xiao
09817c3736 adding general tree code 2025-03-26 13:01:41 -04:00
Jidong Xiao
bed6b5cbc1 about the json library 2025-03-26 13:01:41 -04:00
Jidong Xiao
66d94e8f96 renaming 2025-03-26 13:01:41 -04:00
65 changed files with 1211 additions and 641 deletions

14
.vscode/launch.json vendored
View File

@@ -104,6 +104,20 @@
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"preLaunchTask": "C/C++: g++ build active file"
},
{
"name": "lab07",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [
"input.txt"
],
"cwd": "${fileDirname}",
"environment": [],
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"preLaunchTask": "C/C++: g++ build single active file"
}
]
}

View File

@@ -215,7 +215,7 @@ drawNode(650, 100, '5');
layer.add(line1);
layer.add(line2);
drawNode(500, 200, '3');
drawNode(800, 200, '6');
drawNode(800, 200, '8');
layer.add(line3);
layer.add(line4);
drawNode(350, 300, '2');
@@ -225,7 +225,7 @@ drawNode(700, 300, '7');
layer.add(line6);
layer.add(line7);
drawNode(200, 400, '1');
drawNode(800, 400, '8');
drawNode(800, 400, '7.5');
layer.add(line8);
line8.hide();
layer.draw();
@@ -365,19 +365,44 @@ function nextstep() {
stage.find('#nullptr').show();
layer.draw();
}else if(key == 5){
}else if(key == 6){
if(pc==1){
// highlight 7 (the left most node of the right subtree)
stage.find('#node_'+7).fill("orange");
layer.draw();
pc = pc + 1;
}else if(pc==2){
// update 5 to 7, and restore color to normal
stage.find('#node_text_'+5).text("7");
stage.find('#node_'+5).fill("lightgray");
layer.draw();
pc = pc + 1;
}else if(pc==3){
// and then delete 7 - let 7.5 take over
line7.hide();
stage.find('#node_'+7).hide();
stage.find('#node_text_'+7).hide();
// move 7.5 to 7
stage.find('#node_'+7.5).x(700);
stage.find('#node_'+7.5).y(300);
stage.find('#node_text_'+7.5).x(695);
stage.find('#node_text_'+7.5).y(290);
hidden_7=1;
layer.draw();
pc = pc + 1;
}
}else if(key == 8){
line5.hide();
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
// move 7 and 8
// move 7 and 7.5
stage.find('#node_'+7).x(800);
stage.find('#node_'+7).y(200);
stage.find('#node_text_'+7).x(795);
stage.find('#node_text_'+7).y(190);
stage.find('#node_'+8).x(950);
stage.find('#node_'+8).y(300);
stage.find('#node_text_'+8).x(945);
stage.find('#node_text_'+8).y(290);
stage.find('#node_'+7.5).x(950);
stage.find('#node_'+7.5).y(300);
stage.find('#node_text_'+7.5).x(945);
stage.find('#node_text_'+7.5).y(290);
line7.hide();
line8.show();
hidden_6=1;
@@ -386,13 +411,14 @@ function nextstep() {
line7.hide();
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#node_'+8).x(700);
stage.find('#node_'+8).y(300);
stage.find('#node_text_'+8).x(695);
stage.find('#node_text_'+8).y(290);
// move 7.5 to 7
stage.find('#node_'+7.5).x(700);
stage.find('#node_'+7.5).y(300);
stage.find('#node_text_'+7.5).x(695);
stage.find('#node_text_'+7.5).y(290);
hidden_7=1;
layer.draw();
}else if(key == 8){
}else if(key == 7.5){
// hide this node, and show a NULL pointer.
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();

View File

@@ -8,7 +8,7 @@
<body>
<h1>Recursive Program: Delete a Node in a Binary Search Tree</h1>
<p>This animation shows how to delete a node in a binary search tree. Click the "next step" button to run the animation. <b>Note:</b> This animation as of now doesn't support the deletion of node 5.</p>
<p>This animation shows how to delete a node in a binary search tree. Click the "next step" button to run the animation.</p>
<label>delete node</label> <input type="text" id="textIn"><button onclick="start()">Start</button>
<br>

View File

@@ -128,7 +128,7 @@ Search Engines like Google will search all types of files on the Internet, but i
The search engine you implement will not search anything on the Internet, as that requires extensive knowledge in computer networks and will need to include network libraries, which is way beyond the scope of this course. In this assignment, we limit our searches to a local folder, which is provided as [html_files](html_files).
You are also not allowed to use file system libraries such as &lt;filesystem&gt; to access the HTML files, rather, you should follow the instructions given in the [other useful code](#other-useful-code) section to open HTML files and follow links within each HTML file to get to other HTML files.
You are also not allowed to use file system libraries such as &lt;filesystem&gt; or &lt;dirent&gt;to access the HTML files, rather, you should follow the instructions given in the [other useful code](#other-useful-code) section to open HTML files and follow links within each HTML file to get to other HTML files.
## Supported Commands
@@ -401,7 +401,7 @@ A2: All 33 documents.
- Poor choice of variable names: non-descriptive names (e.g. 'vec', 'str', 'var'), single-letter variable names (except single loop counter), etc. (-2)
- DATA REPRESENTATION (7 pts)
- Uses data structures which have not been covered in this class. (-7)
- Uses filesystem library (i.e., #include &lt;filesystem&gt; ). (-7)
- Uses filesystem library (i.e., #include &lt;filesystem&gt; or #include &lt;dirent&gt;). (-7)
- Neither std::map nor std::set is used. (-7)
- Paths to all 32 HTML files are manually specified within the program's code. (The paths should be found by the program during runtime) (-5)
- RECURSION (3 pts)

View File

@@ -286,10 +286,10 @@ Of course you can change std::cout to a file stream so as to print the thumbs up
In this assignment, you are required to maintain the comments in tree nodes, each comment should be stored in one tree node. **You must use recursion in your program in at least one of your functions.** There is no other requirement on what data structures you can use and what data structures you can not use.
Use good coding style when you design and implement your program. Organize your program into functions: dont put all the code in main! Be sure to read the [Homework Policies](https://www.cs.rpi.edu/academics/courses/spring24/csci1200/homework_policies.php) as you put the finishing touches on your solution. Be sure to make up new test cases to fully debug your program and dont forget to comment your code! Use the provided template [README.txt](./README.txt) file for notes you want the grader to read.
You must do this assignment on your own, as described in the [Collaboration Policy & Academic Integrity](https://www.cs.rpi.edu/academics/courses/spring24/csci1200/academic_integrity.php) page. If you did discuss the problem or error messages, etc. with anyone, please list their names in your README.txt file.
Use good coding style when you design and implement your program. Organize your program into functions: dont put all the code in main! Be sure to read the [Homework Policies](https://www.cs.rpi.edu/academics/courses/spring25/csci1200/homework_policies.php) as you put the finishing touches on your solution. Be sure to make up new test cases to fully debug your program and dont forget to comment your code! Use the provided template [README.txt](./README.txt) file for notes you want the grader to read.
You must do this assignment on your own, as described in the [Collaboration Policy & Academic Integrity](https://www.cs.rpi.edu/academics/courses/spring25/csci1200/academic_integrity.php) page. If you did discuss the problem or error messages, etc. with anyone, please list their names in your README.txt file.
**Due Date**: 03/28/2024, Thursday, 10pm.
**Due Date**: 03/27/2025, Thursday, 10pm.
## Instructor's Code
@@ -301,6 +301,10 @@ Q1: Why sometimes the reply count does not match with the number of replies disp
A1: On youtube, some inappropriate comments are not displayed but they still contribute to the reply count. And such comments are not included in our json files.
Q2: Can I use the <nlohmann/json.hpp> to parse the json file?
A2: It's not that we allow you or we don't allow you to use that json library, it's just that Submitty does not have this library.
## Rubric
17 pts
@@ -319,7 +323,6 @@ A1: On youtube, some inappropriate comments are not displayed but they still con
- Overly cramped, excessive whitespace, or poor indentation. (-1)
- Poor file organization: Puts more than one class in a file (okay for very small helper classes) (-1)
- Poor choice of variable names: non-descriptive names (e.g. 'vec', 'str', 'var'), single-letter variable names (except single loop counter), etc. (-2)
- Contains useless comments like commented-out code, terminal commands, or silly notes. (-1)
- DATA REPRESENTATION (6 pts)
- Does not use tree data structures to store the comments. (-6)
- RECURSION (2 pts)

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -2249,7 +2249,7 @@
{"video_id": "qExVlz3zb0k", "author": "@jpangello4136", "comment_id": "UgwyC9wpy1Hq3XDqAKZ4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "8 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Up"}
{"video_id": "qExVlz3zb0k", "author": "@jpangello4136", "comment_id": "UgyQCmZzN5nJ3URvN6p4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Up"}
{"video_id": "qExVlz3zb0k", "author": "@maxcastter9687", "comment_id": "Ugxbk0p5k-hdDILibHV4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "3 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Britney makes a video with Anitta"}
{"video_id": "qExVlz3zb0k", "author": "@tintifucks", "comment_id": "Ugw3UW7H95lGTUqmwLp4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Original song goosebumps and lots of feelings. This one here has no soul at all! Waste of internet space."}
{"video_id": "qExVlz3zb0k", "author": "@tintif****", "comment_id": "Ugw3UW7H95lGTUqmwLp4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Original song goosebumps and lots of feelings. This one here has no soul at all! Waste of internet space."}
{"video_id": "qExVlz3zb0k", "author": "@shaynejames5715", "comment_id": "UgyAG0cXJqc6DilY-ch4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "2 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Rest In Peace Bank Robber5(hard). U?"}
{"video_id": "qExVlz3zb0k", "author": "@nangio08", "comment_id": "UgyssCU1bycj-k8H6Zh4AaABAg", "like_count": 2, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "4 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "1❤r qG161q"}
{"video_id": "qExVlz3zb0k", "author": "@zolyhaly894", "comment_id": "Ugw6WkCYiB5VvM2O1oV4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "9 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "WEF AGENDA ?"}
@@ -2305,8 +2305,8 @@
{"video_id": "qExVlz3zb0k", "author": "@slammerjaxlive", "comment_id": "UgwyVumM1PlA2xF1GGN4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "2 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "lame 😵"}
{"video_id": "qExVlz3zb0k", "author": "@mariatavares7203", "comment_id": "Ugzhk1DBIkT0vlU4lAx4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "8 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Why is her voice always tweeked? No real talent. She never carried a real tune."}
{"video_id": "qExVlz3zb0k", "author": "@sarahcosgrove6771", "comment_id": "UgycmTk6EzGyiwyobcd4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "This sounds like Miley Cyrus"}
{"video_id": "qExVlz3zb0k", "author": "@veyselamynas8592", "comment_id": "Ugy07XQi6Ad5nGRe99d4AaABAg", "like_count": 0, "reply_count": 1, "is_reply": false, "parent_comment_id": "", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "FCKNGGA"}
{"video_id": "qExVlz3zb0k", "author": "@veyselamynas8592", "comment_id": "Ugy07XQi6Ad5nGRe99d4AaABAg.9qDlppWqcYV9qDm-vbOm3V", "like_count": 0, "reply_count": 0, "is_reply": true, "parent_comment_id": "Ugy07XQi6Ad5nGRe99d4AaABAg", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "KLLALNGGA"}
{"video_id": "qExVlz3zb0k", "author": "@veyselamynas8592", "comment_id": "Ugy07XQi6Ad5nGRe99d4AaABAg", "like_count": 0, "reply_count": 1, "is_reply": false, "parent_comment_id": "", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "F******"}
{"video_id": "qExVlz3zb0k", "author": "@veyselamynas8592", "comment_id": "Ugy07XQi6Ad5nGRe99d4AaABAg.9qDlppWqcYV9qDm-vbOm3V", "like_count": 0, "reply_count": 0, "is_reply": true, "parent_comment_id": "Ugy07XQi6Ad5nGRe99d4AaABAg", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "K********"}
{"video_id": "qExVlz3zb0k", "author": "@Khorine", "comment_id": "UgxWZef6LNBLe_dtHkN4AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "7 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "this song is a bastardised version of the original, sounds like complete trash, what a dogshit edit of a great song"}
{"video_id": "qExVlz3zb0k", "author": "@rebekahgeisen1014", "comment_id": "UgyoOl2UgVdWk-wP2hx4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "7 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "0 ehjsjwojjejkehieibkejjrnknbrnbndmdmmdndkendkgejehehehhjehjehehejejjeehhehehehshhehehhsheuehehehjejjjejjjejbnnejjikj"}
{"video_id": "qExVlz3zb0k", "author": "@annikaheld5513", "comment_id": "UgwbGcqbjTPR9H63YVN4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 months ago", "crawled_date": "2023-10-29T21:26:39.024635", "is_video_owner": false, "comment": "Irgendwie langweilig😮"}

View File

@@ -724,7 +724,7 @@
{"video_id": "zz42pQ-2ytI", "author": "@Wilo-oz2fm", "comment_id": "Ugz7tBfqCKAaQ_eHDCl4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Ronaldo was right ;)"}
{"video_id": "zz42pQ-2ytI", "author": "@patricklopez-mikovich5717", "comment_id": "UgzMKIPvgibzgIvjfDB4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "1 hour ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Manchester is blue and dont say that I dont know what Im talking about but this team would beat 2008 Man utd"}
{"video_id": "zz42pQ-2ytI", "author": "@joemagana5355", "comment_id": "UgyTqZ_EAbBYVXHvFUp4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "4 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Ten Hag is a toxic manager, can't wait till he's gone"}
{"video_id": "zz42pQ-2ytI", "author": "@md8744", "comment_id": "Ugweu6di6xd79kOO2Oh4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Whole world ask fucking MU to eliminate Mcwire but they're very stubborn, play with MC, Liverpool, Tottenham Mcwire would be a kid for them"}
{"video_id": "zz42pQ-2ytI", "author": "@md8744", "comment_id": "Ugweu6di6xd79kOO2Oh4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Whole world ask ****ing MU to eliminate Mcwire but they're very stubborn, play with MC, Liverpool, Tottenham Mcwire would be a kid for them"}
{"video_id": "zz42pQ-2ytI", "author": "@miguel323ish", "comment_id": "UgwuHJZvIZ_arVXAZK94AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "I hate the VAR system"}
{"video_id": "zz42pQ-2ytI", "author": "@meeraaudio", "comment_id": "UgxGg6FEoX2nve_YtRB4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "7 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Ten Hag has to be sacked"}
{"video_id": "zz42pQ-2ytI", "author": "@ndiayeibrahima9876", "comment_id": "UgwUhCYDYoEwGUPfKsV4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "5 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Manchester is blue"}
@@ -756,14 +756,14 @@
{"video_id": "zz42pQ-2ytI", "author": "@goldentotem9437", "comment_id": "UgwjZXIg1tvKvnd_Tv14AaABAg", "like_count": 1, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "58 minutes ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "lol"}
{"video_id": "zz42pQ-2ytI", "author": "@moayadabdullah5842", "comment_id": "Ugzydrx8yalFQF89HSt4AaABAg", "like_count": 0, "reply_count": 1, "is_reply": false, "parent_comment_id": "", "published_date": "4 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Man U goal keeper is a joke"}
{"video_id": "zz42pQ-2ytI", "author": "@Ben2bwild", "comment_id": "Ugzydrx8yalFQF89HSt4AaABAg.9wTSPvTgLud9wTUHLfSUF2", "like_count": 0, "reply_count": 0, "is_reply": true, "parent_comment_id": "Ugzydrx8yalFQF89HSt4AaABAg", "published_date": "4 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "He actually played great. Could have been 8-0. It's obvious you didn't watch the game"}
{"video_id": "zz42pQ-2ytI", "author": "@abp1400", "comment_id": "UgwrYgMRrU1l_v1OKMJ4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "United is nowhere close to City. Glazers need to sell the fuckin team now."}
{"video_id": "zz42pQ-2ytI", "author": "@abp1400", "comment_id": "UgwrYgMRrU1l_v1OKMJ4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "United is nowhere close to City. Glazers need to sell the ****in team now."}
{"video_id": "zz42pQ-2ytI", "author": "@lestersanches6124", "comment_id": "UgyIe6nofMGkVd9pmYx4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "4 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Cr7 is the problem 😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅"}
{"video_id": "zz42pQ-2ytI", "author": "@williamkelley8791", "comment_id": "UgziAmCh370z8-UVY2l4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "7 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "swag"}
{"video_id": "zz42pQ-2ytI", "author": "@angelrincon8392", "comment_id": "UgwIMYIh-aqG3sVRuE94AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "7 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "first!!!💙"}
{"video_id": "zz42pQ-2ytI", "author": "@CarlosCruz-gv8pl", "comment_id": "Ugwdsp2ovteSwr-ToZh4AaABAg", "like_count": 1, "reply_count": 1, "is_reply": false, "parent_comment_id": "", "published_date": "7 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Ronaldo the goat 🐐"}
{"video_id": "zz42pQ-2ytI", "author": "@Javierthegoat", "comment_id": "Ugwdsp2ovteSwr-ToZh4AaABAg.9wTADyeI-vT9wTAKKj6Rr1", "like_count": 0, "reply_count": 0, "is_reply": true, "parent_comment_id": "Ugwdsp2ovteSwr-ToZh4AaABAg", "published_date": "7 hours ago (edited)", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "What does that have to do with the game"}
{"video_id": "zz42pQ-2ytI", "author": "@markramirez68", "comment_id": "UgyqpK8R-xE-EgRsw554AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "2 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Hi"}
{"video_id": "zz42pQ-2ytI", "author": "@Islandman776", "comment_id": "UgwWr-kkj9uuwfRtCCN4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "That wasnt no fucking derby"}
{"video_id": "zz42pQ-2ytI", "author": "@Islandman776", "comment_id": "UgwWr-kkj9uuwfRtCCN4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "6 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "That wasnt no ****ing derby"}
{"video_id": "zz42pQ-2ytI", "author": "@IC_DEAD_BURROS", "comment_id": "UgzZAZzfQ3fjzWttuuN4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "7 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "Bruno is the worst captain in the league . Nothing but a cry baby, throwing tantrum and his arms up in the air in every match, he's not a leader, period."}
{"video_id": "zz42pQ-2ytI", "author": "@unalienablejustice7137", "comment_id": "Ugz2UUp3KK1gTWa5NoJ4AaABAg", "like_count": 0, "reply_count": 0, "is_reply": false, "parent_comment_id": "", "published_date": "4 hours ago (edited)", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "MaN-bOO United lmao 🤣👎\n\nBeat by MaN-shIetty 🤣👎 ... No tap-in for overrated Haaland 🥱"}
{"video_id": "zz42pQ-2ytI", "author": "@reneb.2031", "comment_id": "UgynaY-4eR21du4at_N4AaABAg", "like_count": 1, "reply_count": 4, "is_reply": false, "parent_comment_id": "", "published_date": "7 hours ago", "crawled_date": "2023-10-29T23:00:47.300265", "is_video_owner": false, "comment": "De Gea has to come back 🥲"}

43
labs/maps/checkpoint1.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
int main(int argc, char* argv[]) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " inputfile" << endl;
return 1;
}
ifstream fin(argv[1]);
if (!fin) {
cerr << "Error opening file " << argv[1] << endl;
return 1;
}
// Use operator[] to count frequency of each integer.
map<int, int> counts;
int number;
while (fin >> number) {
counts[number] = counts[number] + 1;
}
// Find the maximum frequency.
int maxCount = 0;
for (map<int, int>::iterator it = counts.begin(); it != counts.end(); ++it) {
if (it->second > maxCount) {
maxCount = it->second;
}
}
// Print all numbers with frequency equal to maxCount.
cout << "Modes: ";
for (map<int, int>::iterator it = counts.begin(); it != counts.end(); ++it) {
if (it->second == maxCount) {
cout << it->first << " ";
}
}
cout << endl;
return 0;
}

BIN
labs/maps/checkpoint2 Executable file

Binary file not shown.

48
labs/maps/checkpoint2.cpp Normal file
View File

@@ -0,0 +1,48 @@
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
int main(int argc, char* argv[]) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " inputfile" << endl;
return 1;
}
ifstream fin(argv[1]);
if (!fin) {
cerr << "Error opening file " << argv[1] << endl;
return 1;
}
// Map to count frequencies; using find/insert instead of operator[].
map<int, int> counts;
int number;
while (fin >> number) {
map<int, int>::iterator it = counts.find(number);
if (it != counts.end()) {
it->second = it->second + 1;
} else {
counts.insert(pair<int, int>(number, 1));
}
}
// Find the maximum frequency.
int maxCount = 0;
for (map<int, int>::iterator it = counts.begin(); it != counts.end(); ++it) {
if (it->second > maxCount) {
maxCount = it->second;
}
}
// Print all numbers with frequency equal to maxCount.
cout << "Modes: ";
for (map<int, int>::iterator it = counts.begin(); it != counts.end(); ++it) {
if (it->second == maxCount) {
cout << it->first << " ";
}
}
cout << endl;
return 0;
}

1
labs/maps/input.txt Normal file
View File

@@ -0,0 +1 @@
19 83 -12 83 65 19 45 -12 45 19 45

BIN
labs/maps/phonebook2 Executable file

Binary file not shown.

42
labs/maps/phonebook2.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include <iostream>
#include <map>
#include <string>
using namespace std;
// Add a number, name pair to the phonebook using a map.
void add(map<int, string>& phonebook, int number, const string &name) {
map<int, string>::iterator it = phonebook.find(number);
if (it != phonebook.end()) {
it->second = name;
} else {
phonebook.insert(pair<int, string>(number, name));
}
}
// Given a phone number, determine who is calling.
void identify(const map<int, string>& phonebook, int number) {
map<int, string>::const_iterator it = phonebook.find(number);
if (it == phonebook.end())
cout << "unknown caller!" << endl;
else
cout << it->second << " is calling!" << endl;
}
int main() {
// Init
map<int, string> phonebook;
// Add
add(phonebook, 1111, "fred");
add(phonebook, 2222, "sally");
add(phonebook, 3333, "george");
add(phonebook, 1234567, "alice");
add(phonebook, 7654321, "bob");
// Test
identify(phonebook, 2222);
identify(phonebook, 4444);
identify(phonebook, 1234567);
return 0;
}

View File

@@ -1,14 +1,22 @@
# Lab 10 — Trees, Binary Trees, & Binary Search Trees
# Lab 8 — Trees, Binary Trees, & Binary Search Trees
## Checkpoint 1
*estimate: 20-30 minutes*
Pair up with one other student in your lab section and complete the exercises below. Please raise your hand and ask for help from a TA or mentor if you get stuck or are uncertain about any of the terms used below.
problem 1: Draw a binary tree with 4 levels with the integers 1-7 such that the sum of elements on every level of the tree is the same.
problem 2: Create a exactly balanced binary search tree with 7 color words (order the colors alphabetically).
problem 3: Draw a exactly-balanced binary search tree containing the letters of the word: uncopyrightable
problem 3: Arrange the following items of clothing in a tree with 3 levels such that the parent of every node is generally donned before the child when dressing in the morning: jacket, pants, shoes, shirt, undergarments, socks, and belt.
problem 4: Draw a binary search tree with the integers 1-7, where 3 has no parent and 5 has no children, and there are no other elements at the same level as 5.
problem 5: What is the sum of the leaf nodes in a perfectly balanced binary search tree containing the powers of 2 less than 128?
problem 6: Draw a exactly-balanced binary search tree containing the letters of the word: uncopyrightable
&nbsp;
&nbsp;
@@ -20,7 +28,7 @@ problem 3: Draw a exactly-balanced binary search tree containing the letters of
What is the pre-order traversal of the tree above?
problem 4: Now draw a exactly-balanced binary tree of characters such that a post-order traversal spells the word: uncopyrightable
problem 7: Now draw a exactly-balanced binary tree of characters such that a post-order traversal spells the word: uncopyrightable
&nbsp;

View File

@@ -34,7 +34,6 @@ public:
// comparions operators are straightforward
bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; }
bool operator!= (const tree_iterator& rgt) { return ptr_ != rgt.ptr_; }
// increment & decrement will be discussed in Lecture 19 and Lab 11
private:
// representation
@@ -93,7 +92,6 @@ private:
// PRIVATE HELPER FUNCTIONS
TreeNode<T>* copy_tree(TreeNode<T>* old_root) {
// Implemented in Lab 10
@@ -106,7 +104,7 @@ private:
}
void destroy_tree(TreeNode<T>* p) { /* Implemented in Lecture 18 */ }
void destroy_tree(TreeNode<T>* p) { }
iterator find(const T& key_value, TreeNode<T>* p) {
if (!p) return iterator(NULL);
@@ -132,7 +130,7 @@ private:
return std::pair<iterator,bool>(iterator(p), false);
}
int erase(T const& key_value, TreeNode<T>* &p) { /* Implemented in Lecture 19 or 20 */ }
int erase(T const& key_value, TreeNode<T>* &p) { }
void print_in_order(std::ostream& ostr, const TreeNode<T>* p) const {
if (p) {

View File

@@ -1,183 +0,0 @@
// Partial implementation of binary-tree based set class similar to std::set.
// The iterator increment & decrement operations have been omitted.
#ifndef ds_set_h_
#define ds_set_h_
#include <iostream>
#include <utility>
// -------------------------------------------------------------------
// TREE NODE CLASS
template <class T>
class TreeNode {
public:
TreeNode() : left(NULL), right(NULL) {}
TreeNode(const T& init) : value(init), left(NULL), right(NULL) {}
T value;
TreeNode* left;
TreeNode* right;
};
// -------------------------------------------------------------------
// TREE NODE ITERATOR CLASS
template <class T>
class tree_iterator {
public:
tree_iterator() : ptr_(NULL) {}
tree_iterator(TreeNode<T>* p) : ptr_(p) {}
tree_iterator(const tree_iterator& old) : ptr_(old.ptr_) {}
~tree_iterator() {}
tree_iterator& operator=(const tree_iterator& old) { ptr_ = old.ptr_; return *this; }
// operator* gives constant access to the value at the pointer
const T& operator*() const { return ptr_->value; }
// comparions operators are straightforward
bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; }
bool operator!= (const tree_iterator& rgt) { return ptr_ != rgt.ptr_; }
private:
// representation
TreeNode<T>* ptr_;
};
// -------------------------------------------------------------------
// DS_SET CLASS
template <class T>
class ds_set {
public:
ds_set() : root_(NULL), size_(0) {}
ds_set(const ds_set<T>& old) : size_(old.size_) {
root_ = this->copy_tree(old.root_); }
~ds_set() {
this->destroy_tree(root_);
root_ = NULL;
}
ds_set& operator=(const ds_set<T>& old) {
if (&old != this) {
this->destroy_tree(root_);
root_ = this->copy_tree(old.root_);
size_ = old.size_;
}
return *this;
}
typedef tree_iterator<T> iterator;
int size() const { return size_; }
bool operator==(const ds_set<T>& old) const { return (old.root_ == this->root_); }
// FIND, INSERT & ERASE
iterator find(const T& key_value) { return find(key_value, root_); }
std::pair< iterator, bool > insert(T const& key_value) { return insert(key_value, root_); }
int erase(T const& key_value) { return erase(key_value, root_); }
// OUTPUT & PRINTING
friend std::ostream& operator<< (std::ostream& ostr, const ds_set<T>& s) {
s.print_in_order(ostr, s.root_);
return ostr;
}
void print_as_sideways_tree(std::ostream& ostr) const {
print_as_sideways_tree(ostr, root_, 0);
}
// ITERATORS
iterator begin() const {
if (!root_) return iterator(NULL);
TreeNode<T>* p = root_;
while (p->left) p = p->left;
return iterator(p);
}
iterator end() const { return iterator(NULL); }
private:
// REPRESENTATION
TreeNode<T>* root_;
int size_;
// PRIVATE HELPER FUNCTIONS
TreeNode<T>* copy_tree(TreeNode<T>* old_root) {
if (old_root == NULL)
return NULL;
TreeNode<T> *answer = new TreeNode<T>();
answer->value = old_root->value;
answer->left = copy_tree(old_root->left);
answer->right = copy_tree(old_root->right);
return answer;
}
void destroy_tree(TreeNode<T>* p) {
if (!p) return;
destroy_tree(p->right);
destroy_tree(p->left);
delete p;
}
iterator find(const T& key_value, TreeNode<T>* p) {
if (!p) return iterator(NULL);
if (p->value > key_value)
return find(key_value, p->left);
else if (p->value < key_value)
return find(key_value, p->right);
else
return iterator(p);
}
std::pair<iterator,bool> insert(const T& key_value, TreeNode<T>*& p) {
if (!p) {
p = new TreeNode<T>(key_value);
this->size_++;
return std::pair<iterator,bool>(iterator(p), true);
}
else if (key_value < p->value)
return insert(key_value, p->left);
else if (key_value > p->value)
return insert(key_value, p->right);
else
return std::pair<iterator,bool>(iterator(p), false);
}
int erase(T const& key_value, TreeNode<T>* &p) {
if (!p) return 0;
// look left & right
if (p->value < key_value)
return erase(key_value, p->right);
else if (p->value > key_value)
return erase(key_value, p->left);
// Found the node. Let's delete it
assert (p->value == key_value);
if (!p->left && !p->right) { // leaf
delete p; p=NULL;
} else if (!p->left) { // no left child
TreeNode<T>* q = p; p=p->right; delete q;
} else if (!p->right) { // no right child
TreeNode<T>* q = p; p=p->left; delete q;
} else { // Find rightmost node in left subtree
TreeNode<T>* &q = p->left;
while (q->right) q = q->right;
p->value = q->value;
int check = erase(q->value, q);
assert (check == 1);
}
return 1;
}
void print_in_order(std::ostream& ostr, const TreeNode<T>* p) const {
if (p) {
print_in_order(ostr, p->left);
ostr << p->value << "\n";
print_in_order(ostr, p->right);
}
}
void print_as_sideways_tree(std::ostream& ostr, const TreeNode<T>* p, int depth) const {
if (p) {
print_as_sideways_tree(ostr, p->right, depth+1);
for (int i=0; i<depth; ++i) ostr << " ";
ostr << p->value << "\n";
print_as_sideways_tree(ostr, p->left, depth+1);
}
}
};
#endif

View File

@@ -1,28 +1,20 @@
#include <iostream>
#include "ds_set_starter.h"
// #include <set>
int main() {
// create a set of integers
std::set<int> numbers;
ds_set<int> numbers;
// insert some values into the set
numbers.insert(10);
numbers.insert(5);
numbers.insert(20);
numbers.insert(15);
numbers.insert(5); // Duplicate value (won't be inserted)
// print the elements of the set
std::cout << "The elements in the set are:" << std::endl;
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
numbers.insert(5); // duplicate value (won't be inserted)
// check if a specific value exists in the set
int value = 15;
if (numbers.find(value) != numbers.end()) {
if (numbers.find(value) == true) {
std::cout << value << " is found in the set." << std::endl;
} else {
std::cout << value << " is not found in the set." << std::endl;

View File

@@ -0,0 +1,31 @@
#include <iostream>
#include <set>
int main() {
// create a set of integers
std::set<int> numbers;
// insert some values into the set
numbers.insert(10);
numbers.insert(5);
numbers.insert(20);
numbers.insert(15);
numbers.insert(5); // duplicate value (won't be inserted)
// print the elements of the set
std::cout << "The elements in the set are:" << std::endl;
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
// check if a specific value exists in the set
int value = 15;
if (numbers.find(value) != numbers.end()) {
std::cout << value << " is found in the set." << std::endl;
} else {
std::cout << value << " is not found in the set." << std::endl;
}
return 0;
}

View File

@@ -3,20 +3,17 @@
## Review from Lecture 18
- Binary Trees, Binary Search Trees, & Balanced Trees
- STL set container class (like STL map, but without the pairs!)
- Finding the smallest element in a BST.
- Overview of the ds set implementation: begin and find. (leetcode 700)
## Todays Lecture
- Warmup / Review: destroy_tree
- A very important ds set operation insert
- In-order, pre-order, and post-order traversal
- Finding the in-order successor of a binary tree node, tree iterator increment
## 19.1 Warmup Exercise
Write the ds set::destroy tree private helper function.
Write the ds set::destroy tree private helper function, which can then be called by the destructor.
## 19.2 Insert
@@ -89,7 +86,7 @@ point to the “in-order predecessor”.
Each node stores a parent pointer. Only the root node has a null parent pointer. [method 1]
Each iterator maintains a stack of pointers representing the path down the tree to the current node. [method 2]
Each iterator maintains a container of pointers representing the path down the tree to the current node. [method 2]
- If we choose the parent pointer method, well need to rewrite the insert and erase member functions to
@@ -99,21 +96,27 @@ easy to show that iterating through a tree storing n nodes requires O(n) operati
Exercise: [method 1] Write a fragment of code that given a node, finds the in-order successor using parent pointers.
Be sure to draw a picture to help you understand!
![alt text](ds_set_parent_ptrs.png "ds set parent ptrs")
Exercise: [method 2] Write a fragment of code that given a tree iterator containing a pointer to the node and a
stack of pointers representing path from root to node, finds the in-order successor (without using parent pointers).
Either version can be extended to complete the implementation of increment/decrement for the ds_set tree iterators.
![alt text](ds_set_history.png "ds set history")
container of pointers representing path from root to node, finds the in-order successor (without using parent pointers).
Either version can be extended to complete the implementation of increment/decrement for the ds_set tree iterators. (This method will be covered in the next lecture)
Exercise: What are the advantages & disadvantages of each method?
<!-- ![alt text](ds_set_history.png "ds set history") -->
<!-- Exercise: What are the advantages & disadvantages of each method? -->
## 19.5 Limitations of Our BST Implementation
- An implementation of a set using a binary search tree is provided in this [ds_set.h](ds_set.h).
- A testing program is provided as well: [ds_set_main.cpp](ds_set_main.cpp).
- The efficiency of the main insert, find and erase algorithms depends on the height of the tree.
- The best-case and average-case heights of a binary search tree storing n nodes are both O(log n). The worstcase, which often can happen in practice, is O(n).
- Developing more sophisticated algorithms to avoid the worst-case behavior will be covered in Introduction to
Algorithms. One elegant extension to the binary search tree is described below...
Algorithms.
<!-- One elegant extension to the binary search tree is described below...
## 19.6 B+ Trees
@@ -133,4 +136,94 @@ implementation).
child must be < key0, the next child must have keys such that they are ≥key0 and < key1, and so on up to
the rightmost child which has only keys ≥keyk1.
A B+ tree visualization can be seen at: https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
A B+ tree visualization can be seen at: https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html -->
## 19.6 N-ary tree and General Tree
- A tree where each node can have many children (not limited to two) is generally called an n-ary tree, where n refers to the maximum number of children each node can have.
- If there is no fixed limit on the number of children, it's often simply referred to as a general tree or multi-way tree. Here is an example:
![alt text](general_tree.png "A general tree example")
- We can define the tree nodes for a general tree like this:
```cpp
class Node {
public:
int val;
std::vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, std::vector<Node*> _children) {
val = _val;
children = _children;
}
};
```
## 19.7 General Tree Pre-order Traversal
The following code implements the pre-order traversal of a general tree.
```cpp
// make a helper function, since the original one doesn't take the vector as a parameter.
void preorder(Node* root, std::vector<int>& result){
if(root == NULL){
return;
}
// visit the parent
result.push_back(root->val);
int size = root->children.size();
for(int i=0; i<size; ++i){
// traverse each subtree
preorder(root->children[i], result);
}
}
std::vector<int> preorder(Node* root) {
std::vector<int> result;
preorder(root, result);
return result;
}
```
You can run [this program](general_tree_pre_order.cpp) to test the above functions.
## 19.8 General Tree Post-order Traversal
The following code implements the post-order traversal of a general tree.
```cpp
// make a helper function, since the original one doesn't take the vector as a parameter.
void postorder(Node* root, std::vector<int>& result){
// base case
if(root==NULL){
return;
}
// children first
int size = (root->children).size();
for(int i=0; i<size; ++i){
// call the same function to traverse children[i]
postorder(root->children[i], result);
}
// then parent
result.push_back(root->val);
}
std::vector<int> postorder(Node* root) {
std::vector<int> result;
postorder(root, result);
return result;
}
```
You can run [this program](general_tree_post_order.cpp) to test the above functions.

View File

@@ -0,0 +1,132 @@
#include <utility> // for std::pair
template <class T>
class TreeNode {
public:
T key;
TreeNode* left;
TreeNode* right;
// one way to allow implementation of iterator increment & decrement
TreeNode* parent;
// constructor
TreeNode(const T& k) {
key = k;
left = NULL;
right = NULL;
}
};
// -------------------------------------------------------------------
// TREE NODE ITERATOR CLASS
template <class T>
class tree_iterator {
public:
tree_iterator() : ptr_(NULL) {}
tree_iterator(TreeNode<T>* p) : ptr_(p) {}
tree_iterator(const tree_iterator& other) : ptr_(other.ptr_) {}
~tree_iterator() {}
tree_iterator& operator=(const tree_iterator& other) { ptr_ = other.ptr_; return *this; }
// operator* gives constant access to the value at the pointer
const T& operator*() const { return ptr_->key; }
// comparison operators are straightforward
bool operator== (const tree_iterator& other) { return ptr_ == other.ptr_; }
bool operator!= (const tree_iterator& other) { return ptr_ != other.ptr_; }
// increment & decrement operators
tree_iterator<T> & operator++() {
// if i have right subtree, find left most element of those
if (ptr_->right != NULL) {
ptr_ = ptr_->right;
while (ptr_->left != NULL) {
ptr_ = ptr_->left;
}
} else {
// keep going up as long as I'm my parent's right child
while (ptr_->parent && ptr_->parent->right == ptr_) {
ptr_ = ptr_->parent;
}
// go up one more time
ptr_ = ptr_->parent;
}
// when we return, ptr_ should point to the destination node.
return *this;
}
tree_iterator<T> operator++(int) { tree_iterator<T> temp(*this); ++(*this); return temp; }
tree_iterator<T> & operator--() { /* implementation omitted */ }
tree_iterator<T> operator--(int) { tree_iterator<T> temp(*this); --(*this); return temp; }
private:
// representation
TreeNode<T>* ptr_;
};
// internally it's a binary search tree
template <class T>
class ds_set {
public:
ds_set(){
root = NULL;
m_size = 0;
}
typedef tree_iterator<T> iterator;
int size() { return m_size; }
iterator find(const T& key){
return find(key, root);
}
std::pair<iterator, bool> insert(const T& key){
std::pair<iterator, bool> temp;
temp = insert(key, root, NULL);
if(temp.second == true){
++m_size;
}
return temp;
}
// ITERATORS
tree_iterator<T> begin() const {
if (!root) return tree_iterator<T>(NULL);
TreeNode<T>* p = root;
while (p->left) {
p = p->left;
}
return tree_iterator<T>(p);
}
tree_iterator<T> end() const { return tree_iterator<T>(NULL); }
private:
TreeNode<T>* root;
int m_size;
iterator find(const T& key, TreeNode<T>* root);
// as there are multiple templated classes involved, writing this function outside of the class definition may be too complicated.
std::pair<iterator, bool> insert(const T& key, TreeNode<T>*& node, TreeNode<T>* parent) {
// base case
if (node == nullptr) {
node = new TreeNode<T>(key);
node->parent = parent;
return { iterator(node), true };
}
if (key < node->key) {
return insert(key, node->left, node);
} else if (key > node->key) {
return insert(key, node->right, node);
} else {
// key already exists
return { iterator(node), false };
}
}
};
template <class T>
typename ds_set<T>::iterator ds_set<T>::find(const T& key, TreeNode<T>* root){
// base case (if root doesn't even exist)
if(root == NULL){
return end();
}
// general case
if(key < root->key){
return find(key, root->left);
}else if(key > root->key){
return find(key, root->right);
}else{
return tree_iterator(root);
}
}

View File

@@ -1,155 +0,0 @@
// -------------------------------------------------------------------
// TREE NODE CLASS
template <class T>
class TreeNode {
public:
TreeNode() : left(NULL), right(NULL)/*, parent(NULL)*/ {}
TreeNode(const T& init) : value(init), left(NULL), right(NULL)/*, parent(NULL)*/ {}
T value;
TreeNode* left;
TreeNode* right;
// one way to allow implementation of iterator increment & decrement
// TreeNode* parent;
};
// -------------------------------------------------------------------
// TREE NODE ITERATOR CLASS
template <class T>
class tree_iterator {
public:
tree_iterator() : ptr_(NULL) {}
tree_iterator(TreeNode<T>* p) : ptr_(p) {}
tree_iterator(const tree_iterator& old) : ptr_(old.ptr_) {}
~tree_iterator() {}
tree_iterator& operator=(const tree_iterator& old) { ptr_ = old.ptr_; return *this; }
// operator* gives constant access to the value at the pointer
const T& operator*() const { return ptr_->value; }
// comparison operators are straightforward
bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; }
bool operator!= (const tree_iterator& rgt) { return ptr_ != rgt.ptr_; }
// increment & decrement operators
tree_iterator<T> & operator++() { /* discussed & implemented in Lecture 18 */
// if i have right subtree, find left most element of those
if (ptr_->right_ != NULL) {
ptr_ = ptr_->right_;
while (ptr_->left != NULL) {
ptr_ = ptr_->left_;
}
} else {
//TreeNode<T> *tmp = ptr_;
// Keep going up as long as I'm my parent's right child
//while (tmp->value < value ) {
while (ptr_->parent && ptr_->parent_->right == ptr_)
ptr_ = ptr_->parent_;
}
// Go up one more time
ptr_ = ptr_->parent;
}
return *this;
}
tree_iterator<T> operator++(int) { tree_iterator<T> temp(*this); ++(*this); return temp; }
tree_iterator<T> & operator--() { /* implementation omitted */ }
tree_iterator<T> operator--(int) { tree_iterator<T> temp(*this); --(*this); return temp; }
private:
// representation
TreeNode<T>* ptr_;
};
// -------------------------------------------------------------------
// DS_SET CLASS
template <class T>
class ds_set {
public:
ds_set() : root_(NULL), size_(0) {}
ds_set(const ds_set<T>& old) : size_(old.size_) { root_ = this->copy_tree(old.root_,NULL); }
~ds_set() { this->destroy_tree(root_); }
ds_set& operator=(const ds_set<T>& old) { /* implementation omitted */ }
typedef tree_iterator<T> iterator;
int size() const { return size_; }
bool operator==(const ds_set<T>& old) const { return (old.root_ == this->root_); }
// FIND, INSERT & ERASE
iterator find(const T& key_value) { return find(key_value, root_); }
std::pair< iterator, bool > insert(T const& key_value) { return insert(key_value, root_); }
int erase(T const& key_value) { return erase(key_value, root_); }
// OUTPUT & PRINTING
friend std::ostream& operator<< (std::ostream& ostr, const ds_set<T>& s) {
s.print_in_order(ostr, s.root_);
return ostr;
}
// ITERATORS
iterator begin() const {
if (!root_) return iterator(NULL);
TreeNode<T>* p = root_;
while (p->left) p = p->left;
return iterator(p);
}
iterator end() const { return iterator(NULL); }
private:
// REPRESENTATION
TreeNode<T>* root_;
int size_;
// PRIVATE HELPER FUNCTIONS
TreeNode<T>* copy_tree(TreeNode<T>* old_root) { /* Implemented in Lab 9 */ }
void destroy_tree(TreeNode<T>* p) {
if (!p) return;
destroy_tree(p->left);
destroy_tree(p->right);
delete p;
}
/*void destroy_tree(TreeNode<T>* & p) {
// Implemented in Lecture 19
if (!p) {
p = NULL;
size = 0;
return;
}
destroy_tree(p->left);
TreeNode<T>* tmp = p->right;
delete p;
destroy_tree(tmp);
}
*/
}
iterator find(const T& key_value, TreeNode<T>* p) { /* Implemented in Lecture 17 */ }
std::pair<iterator,bool> insert(const T& key_value, TreeNode<T>*& p) {
// NOTE: will need revision to support & maintain parent pointers
if (!p) {
p = new TreeNode<T>(key_value);
this->size_++;
return std::pair<iterator,bool>(iterator(p), true);
}
else if (key_value < p->value)
return insert(key_value, p->left);
else if (key_value > p->value)
return insert(key_value, p->right);
else
return std::pair<iterator,bool>(iterator(p), false);
}
int erase(T const& key_value, TreeNode<T>* &p) { /* Implemented in Lecture 19 */ }
void print_in_order(std::ostream& ostr, const TreeNode<T>* p) const {
if (p) {
print_in_order(ostr, p->left);
ostr << p->value << "\n";
print_in_order(ostr, p->right);
}
}
};

View File

@@ -1,130 +0,0 @@
// -------------------------------------------------------------------
// TREE NODE CLASS
template <class T>
class TreeNode {
public:
TreeNode() : left(NULL), right(NULL)/*, parent(NULL)*/ {}
TreeNode(const T& init) : value(init), left(NULL), right(NULL)/*, parent(NULL)*/ {}
T value;
TreeNode* left;
TreeNode* right;
// one way to allow implementation of iterator increment & decrement
// TreeNode* parent;
};
// -------------------------------------------------------------------
// TREE NODE ITERATOR CLASS
template <class T>
class tree_iterator {
public:
tree_iterator() : ptr_(NULL) {}
tree_iterator(TreeNode<T>* p) : ptr_(p) {}
tree_iterator(const tree_iterator& old) : ptr_(old.ptr_) {}
~tree_iterator() {}
tree_iterator& operator=(const tree_iterator& old) { ptr_ = old.ptr_; return *this; }
// operator* gives constant access to the value at the pointer
const T& operator*() const { return ptr_->value; }
// comparions operators are straightforward
bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; }
bool operator!= (const tree_iterator& rgt) { return ptr_ != rgt.ptr_; }
// increment & decrement operators
tree_iterator<T> & operator++() { /* discussed & implemented in Lecture 19 */
return *this;
}
tree_iterator<T> operator++(int) { tree_iterator<T> temp(*this); ++(*this); return temp; }
tree_iterator<T> & operator--() { /* implementation omitted */ }
tree_iterator<T> operator--(int) { tree_iterator<T> temp(*this); --(*this); return temp; }
private:
// representation
TreeNode<T>* ptr_;
};
// -------------------------------------------------------------------
// DS_SET CLASS
template <class T>
class ds_set {
public:
//CONSTRUCTORS, DESTRUCTORS, ASSIGNMENT OPERATOR
ds_set() : root_(NULL), size_(0) {}
ds_set(const ds_set<T>& old) : size_(old.size_) { root_ = this->copy_tree(old.root_,NULL); }
~ds_set() { this->destroy_tree(root_); root_ = NULL; }
ds_set& operator=(const ds_set<T>& old) { /* implementation omitted */ }
typedef tree_iterator<T> iterator;
int size() const { return size_; }
bool operator==(const ds_set<T>& old) const { return (old.root_ == this->root_); }
// FIND, INSERT & ERASE
iterator find(const T& key_value) { return find(key_value, root_); }
std::pair< iterator, bool > insert(T const& key_value) { return insert(key_value, root_); }
int erase(T const& key_value) { return erase(key_value, root_); }
// OUTPUT & PRINTING
friend std::ostream& operator<< (std::ostream& ostr, const ds_set<T>& s) {
s.print_in_order(ostr, s.root_);
return ostr;
}
// ITERATORS
iterator begin() const {
if (!root_) return iterator(NULL);
TreeNode<T>* p = root_;
while (p->left) p = p->left;
return iterator(p);
}
iterator end() const { return iterator(NULL); }
private:
// REPRESENTATION
TreeNode<T>* root_;
int size_;
// PRIVATE HELPER FUNCTIONS
TreeNode<T>* copy_tree(TreeNode<T>* old_root) { /* Implemented in Lab 9 */ }
void destroy_tree(TreeNode<T>* p) {
/* Implemented in Lecture 18 */
}
iterator find(const T& key_value, TreeNode<T>* p) { /* Implemented in Lecture 17 */ }
std::pair<iterator,bool> insert(const T& key_value, TreeNode<T>*& p) {
// NOTE: will need revision to support & maintain parent pointers
if (!p) {
p = new TreeNode<T>(key_value);
this->size_++;
return std::pair<iterator,bool>(iterator(p), true);
}
else if (key_value < p->value)
return insert(key_value, p->left);
else if (key_value > p->value)
return insert(key_value, p->right);
else
return std::pair<iterator,bool>(iterator(p), false);
}
int erase(T const& key_value, TreeNode<T>* &p) { /* Implemented in Lecture 19 */ }
void print_in_order(std::ostream& ostr, const TreeNode<T>* p) const {
if (p) {
print_in_order(ostr, p->left);
ostr << p->value << "\n";
print_in_order(ostr, p->right);
}
}
};

View File

@@ -0,0 +1,42 @@
#include <iostream>
#include "ds_set.h"
int main() {
// create a set of integers
ds_set<int> numbers;
// insert some values into the set
numbers.insert(10);
numbers.insert(5);
numbers.insert(88);
numbers.insert(20);
numbers.insert(49);
numbers.insert(15);
numbers.insert(36);
numbers.insert(5); // Duplicate value (won't be inserted)
// print the elements of the set
std::cout << "The elements in the set are:" << std::endl;
for(ds_set<int>::iterator itr = numbers.begin(); itr != numbers.end(); ++itr){
std::cout << *itr << " ";
}
std::cout << std::endl;
// check if a specific value exists in the set
int value = 15;
if (numbers.find(value) != numbers.end()) {
std::cout << value << " is found in the set." << std::endl;
} else {
std::cout << value << " is not found in the set." << std::endl;
}
// check if a specific value exists in the set
value = 66;
if (numbers.find(value) != numbers.end()) {
std::cout << value << " is found in the set." << std::endl;
} else {
std::cout << value << " is not found in the set." << std::endl;
}
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,79 @@
#include <iostream>
#include <vector>
class Node {
public:
int val;
std::vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, std::vector<Node*> _children) {
val = _val;
children = _children;
}
};
// make a helper function, since the original one doesn't take the vector as a parameter.
void postorder(Node* root, std::vector<int>& result){
// base case
if(root==NULL){
return;
}
// children first
int size = (root->children).size();
for(int i=0; i<size; ++i){
// call the same function to traverse children[i]
postorder(root->children[i], result);
}
// then parent
result.push_back(root->val);
}
std::vector<int> postorder(Node* root) {
std::vector<int> result;
postorder(root, result);
return result;
}
int main() {
// create tree nodes
// 1
// / | \
// 2 3 4
// / \
// 5 6
Node* node5 = new Node(5);
Node* node6 = new Node(6);
Node* node2 = new Node(2);
Node* node3 = new Node(3, {node5, node6});
Node* node4 = new Node(4);
Node* root = new Node(1, {node2, node3, node4});
// call preorder traversal
std::vector<int> result = postorder(root);
// print result
std::cout << "Post-order traversal: ";
for (int val : result) {
std::cout << val << " ";
}
std::cout << std::endl;
// free memory (optional but good practice)
delete node5;
delete node6;
delete node2;
delete node3;
delete node4;
delete root;
return 0;
}

View File

@@ -0,0 +1,76 @@
#include <iostream>
#include <vector>
class Node {
public:
int val;
std::vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, std::vector<Node*> _children) {
val = _val;
children = _children;
}
};
// make a helper function, since the original one doesn't take the vector as a parameter.
void preorder(Node* root, std::vector<int>& result){
if(root == NULL){
return;
}
result.push_back(root->val);
// general case
int size = (root->children).size();
for(int i=0; i<size; ++i){
preorder(root->children[i], result);
}
}
std::vector<int> preorder(Node* root) {
std::vector<int> result;
preorder(root, result);
return result;
}
int main() {
// create tree nodes
// 1
// / | \
// 2 3 4
// / \
// 5 6
Node* node5 = new Node(5);
Node* node6 = new Node(6);
Node* node2 = new Node(2);
Node* node3 = new Node(3, {node5, node6});
Node* node4 = new Node(4);
Node* root = new Node(1, {node2, node3, node4});
// call preorder traversal
std::vector<int> result = preorder(root);
// print result
std::cout << "Pre-order traversal: ";
for (int val : result) {
std::cout << val << " ";
}
std::cout << std::endl;
// free memory
// FIXME: here we delete node one by one, which is really bad, we should write a function to delete the tree.
delete node5;
delete node6;
delete node2;
delete node3;
delete node4;
delete root;
return 0;
}

View File

@@ -6,21 +6,18 @@ Review from Lecture 18 & 19
- In-order, pre-order, and post-order traversal;
- Iterator implementation. Finding the in order successor to a node: add parent pointers or add a list/vector/stack
of pointers to the iterator.
- B+ Tree Overview
<!-- - B+ Tree Overview -->
## Todays Lecture
- Breadth-first and depth-first tree search
- Increement/decrement operator
- Tree height, longest-shortest paths, breadth-first search
- Second approach of iterator increement/decrement operator
- Last piece of ds_set: removing an item, erase
- Erase with parent pointers, increment operation on iterators
- Limitations of our ds set implementation
- Breadth-first and depth-first tree search
## 20.1 ds_set Warmup/Review Exercises
- Draw a diagram of a possible memory layout for a ds set containing the numbers 16, 2, 8, 11, and 5. Is there
only one valid memory layout for this data as a ds set? Why?
- Draw a diagram of a possible memory layout for a ds_set containing the numbers 16, 2, 8, 11, and 5. Is there
only one valid memory layout for this data as a ds_set? Why?
&nbsp;
&nbsp;
@@ -39,56 +36,13 @@ only one valid memory layout for this data as a ds set? Why?
&nbsp;
&nbsp;
## 20.2 Depth-first vs. Breadth-first Search
## 20.2 Second Approach of Operator++
- We should also discuss two other important tree traversal terms related to problem solving and searching.
- In a depth-first search, we greedily follow links down into the tree, and dont backtrack until we have hit a leaf. When we hit a leaf we step back out, but only to the last decision point and then proceed to the next leaf. This search method will quickly investigate leaf nodes, but if it has made an “incorrect” branch decision early in the search, it will take a long time to work back to that point and go down the “right” branch.
We can also implement operator++ for the ds_set iterator without using the parent pointers. To achieve this, we need a container of pointers representing path from root to node. The following diagram represents the idea, and the code is provided here: [ds_set_ptrs.h](ds_set_ptrs.h) and [ds_set_main.cpp](ds_set_main.cpp).
- In a breadth-first search, the nodes are visited with priority based on their distance from the root, with nodes closer to the root visited first. In other words, we visit the nodes by level, first the root (level 0), then all children of the root (level 1), then all nodes 2 links from the root (level 2), etc. If there are multiple solution nodes, this search method will find the solution node with the shortest path to the root node. However, the breadth-first search method is memory-intensive, because the implementation must store all nodes at the current level and the worst case number of nodes on each level doubles as we progress down the tree!
![alt text](ds_set_history.png "ds set history")
- Both depth-first and breadth-first will eventually visit all elements in the tree.
- Note: The ordering of elements visited by depth-first and breadth-first is not fully specified.
- In-order, pre-order, and post-order are all examples of depth-first tree traversals. Note: A simple recursive tree function is usually a depth-first traversal.
- What is a breadth-first traversal of the elements in our sample binary search trees above?
## 20.3 General-Purpose Breadth-First Search/Tree Traversal
- Write an algorithm to print the nodes in the tree one tier at a time, that is, in a breadth-first manner.
```cpp
BFS code discussed in class
void breadth_first_traverse(Node* root)
{
int level=0;
std::vector<Node*> current_level;
std::vector<Node*> next_level;
if(root==NULL){return;}
current_level.push_back(root);
while(current_level.size()!=0)
{
std::cout<<"level"<<level<<":";
for (unsigned i=0; i<current_level.size();i++)
{
if(current_level[i]->left != NULL)
next_level.push_back(current_level[i]->left);
if(current_level[i]->right != NULL)
next_level.push_back(current_level[i]->right);
std::cout<<" "<<current_level[i]->value;
}
current_level = next_level;
level++;
next_level.clear();
std::cout<<std.endl;
}
}
```
- What is the best/average/worst-case running time of this algorithm? What is the best/average/worst-case
memory usage of this algorithm? Give a specific example tree that illustrates each case.
## 20.4 Height and Height Calculation Algorithm
<!-- ## 20.5 Height and Height Calculation Algorithm
- The height of a node in a tree is the length of the longest path down the tree from that node to a leaf node. The height of a tree with only one node (the root node) is 1. The height of an empty tree (a tree with no nodes) is 0.
@@ -131,7 +85,7 @@ unsigned int height(Node* p)
}
```
## 20.5 Shortest Paths to Leaf Node
## 20.6 Shortest Paths to Leaf Node
- Now lets write a function to instead calculate the shortest path to a NULL child pointer.
&nbsp;
@@ -171,8 +125,9 @@ void shortest_path_breadth(Node* root)
&nbsp;
&nbsp;
&nbsp;
-->
## 20.6 Erase
## 20.3 Erase
- First we need to find the node to remove. Once it is found,
the actual removal is easy if the node has no children or only one child.
@@ -184,13 +139,48 @@ Draw picture of each case!
- Then we recursively apply erase to remove that node — which is guaranteed to have at most one child.
Exercise: Write a recursive version of erase.
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
Play this [animation](https://jidongxiao.github.io/CSCI1200-DataStructures/animations/trees/delete_node/index.html) to understand how this works.
- An erase function is provided here:
```cpp
void eraseHelper(const T& key, TreeNode<T>*& root){
if (root == NULL) return;
if (root->key == key) {
if (root->left == NULL && root->right == NULL){
// no child, just delete
delete root;
root = NULL;
} else if (root->left == NULL){
// doesn't have a left, let the right child take over
TreeNode<T>* temp = root;
root = root->right;
delete temp;
} else if (root->right == NULL){
// doesn't have a right, let the left child take over
TreeNode<T>* temp = root;
root = root->left;
delete temp;
} else {
// has both left and right
// let the leftmost node of the right subtree take over
TreeNode<T>* tmp = root->right;
while (tmp->left) {
tmp = tmp->left;
}
root->key = tmp->key;
// but then remove that leftmost node of the right subtree.
eraseHelper(tmp->key, root->right);
}
} else if (root->key > key) {
// search on the left subtree and erase
eraseHelper(key, root->left);
} else {
// search on the right subtree and erase
eraseHelper(key, root->right);
}
}
```
Exercise: How does the order that nodes are deleted affect the tree structure? Starting with a mostly balanced
tree, give an erase ordering that yields an unbalanced tree.
@@ -201,60 +191,8 @@ tree, give an erase ordering that yields an unbalanced tree.
&nbsp;
&nbsp;
```cpp
Code for function ERASE built in class so remember it has not been executed yet and may require some fixes here and there.
int erase (T const& key_value, TreeNode* &p){
if (p->value == key_value)
{
if (p->left == NULL && p->right == NULL)
{
delete p;
p=NULL;
return 1;
}
else if (p->left == NULL)
{
TreeNode* tmp = p->right;
tmp->parent = p->parent;
delete p;
p=tmp;
return 1;
}
else if (p->right == NULL)
{
TreeNode* tmp = p->left;
tmp->parent = p->parent;
delete p;
p=tmp;
return 1;
}
else
{ //reusing begin logic
TreeNode* tmp = p->left;
while(tmp -> right)
tmp = tmp->right;
p->value = tmp->value;
return erase(p->value, tmp);
}
}
else if (p-> value < key_value)
{
return erase(key_value, p->right);
}
else
{
assert (p->value > key_value);
return erase (key_value, p->left);
}
return 0;
}
}
```
## 20.7 Erase (now with parent pointers)
<!--
## 20.8 Erase (now with parent pointers)
- If we choose to use parent pointers, we need to add to the Node representation, and re-implement several ds_set member functions.
- Exercise: Study the new version of insert, with parent pointers.
@@ -266,4 +204,67 @@ return 0;
&nbsp;
&nbsp;
&nbsp;
-->
## 20.4 Depth-first vs. Breadth-first Search
- We should also discuss two other important tree traversal terms related to problem solving and searching.
- In a depth-first search, we greedily follow links down into the tree, and dont backtrack until we have hit a leaf. When we hit a leaf we step back out, but only to the last decision point and then proceed to the next leaf. This search method will quickly investigate leaf nodes, but if it has made an “incorrect” branch decision early in the search, it will take a long time to work back to that point and go down the “right” branch.
- In a breadth-first search, the nodes are visited with priority based on their distance from the root, with nodes closer to the root visited first. In other words, we visit the nodes by level, first the root (level 0), then all children of the root (level 1), then all nodes 2 links from the root (level 2), etc. If there are multiple solution nodes, this search method will find the solution node with the shortest path to the root node. However, the breadth-first search method is memory-intensive, because the implementation must store all nodes at the current level and the worst case number of nodes on each level doubles as we progress down the tree!
- Both depth-first and breadth-first will eventually visit all elements in the tree.
- Note: The ordering of elements visited by depth-first and breadth-first is not fully specified.
- In-order, pre-order, and post-order are all examples of depth-first tree traversals. Note: A simple recursive tree function is usually a depth-first traversal.
- What is a breadth-first traversal of the elements in our sample binary search trees above?
## 20.5 General-Purpose Breadth-First Search/Tree Traversal
- Write an algorithm to print the nodes in the tree one tier at a time, that is, in a breadth-first manner.
```cpp
// the breadth-first traversal function using std::queue
void breadth_first_traverse(Node* root) {
if (root == NULL) {
return;
}
std::queue<Node*> node_queue; // queue to store nodes for BFS traversal
node_queue.push(root); // start by pushing the root node
int level = 0;
while (!node_queue.empty()) {
int level_size = node_queue.size(); // number of nodes at the current level
std::cout << "level " << level << ": ";
for (int i = 0; i < level_size; i++) {
Node* current_node = node_queue.front(); // get the front node
node_queue.pop(); // remove the node from the queue
std::cout << current_node->value << " "; // print the value of the node
// push the children of the current node to the queue (if they exist)
if (current_node->left != NULL) {
node_queue.push(current_node->left);
}
if (current_node->right != NULL) {
node_queue.push(current_node->right);
}
}
// after we finish the for loop, the only pointers in the queue, are the pointers pointing to nodes of the next level.
std::cout << std::endl;
level++;
}
}
```
- What is the best/average/worst-case running time of this algorithm? What is the best/average/worst-case
memory usage of this algorithm? Give a specific example tree that illustrates each case.
- Run [this bfs_main.cpp program](bfs_main.cpp) to test the above function.
- Play this [animation](https://jidongxiao.github.io/CSCI1200-DataStructures/animations/trees/level_order/index.html) to understand how this works.

View File

@@ -0,0 +1,78 @@
#include <iostream>
#include <queue>
class Node {
public:
int value;
Node* left;
Node* right;
// constructor to create a new node
Node(int val) : value(val), left(NULL), right(NULL) {}
};
// the breadth-first traversal function using std::queue
void breadth_first_traverse(Node* root) {
if (root == NULL) {
return;
}
std::queue<Node*> node_queue; // queue to store nodes for BFS traversal
node_queue.push(root); // start by pushing the root node
int level = 0;
while (!node_queue.empty()) {
int level_size = node_queue.size(); // number of nodes at the current level
std::cout << "level " << level << ": ";
for (int i = 0; i < level_size; i++) {
Node* current_node = node_queue.front(); // get the front node
node_queue.pop(); // remove the node from the queue
std::cout << current_node->value << " "; // print the value of the node
// push the children of the current node to the queue (if they exist)
if (current_node->left != NULL) {
node_queue.push(current_node->left);
}
if (current_node->right != NULL) {
node_queue.push(current_node->right);
}
}
// after we finish the for loop, the only pointers in the queue, are the pointers pointing to nodes of the next level.
std::cout << std::endl;
level++;
}
}
int main() {
// creating a simple binary tree
// 1
// / \
// 2 3
// / \ / \
//4 5 6 7
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
// calling the breadth-first traversal function
breadth_first_traverse(root);
// cleaning up dynamically allocated memory
delete root->left->left;
delete root->left->right;
delete root->right->left;
delete root->right->right;
delete root->left;
delete root->right;
delete root;
return 0;
}

View File

@@ -0,0 +1,72 @@
#include <iostream>
#include <vector>
class Node {
public:
int value;
Node* left;
Node* right;
// constructor to create a new node
Node(int val) : value(val), left(NULL), right(NULL) {}
};
// bfs using vectors
void breadth_first_traverse(Node* root) {
int level = 0;
std::vector<Node*> current_level;
std::vector<Node*> next_level;
if (root == NULL) {
return;
}
current_level.push_back(root);
while (current_level.size() != 0) {
std::cout << "level " << level << ":";
for (unsigned i = 0; i < current_level.size(); i++) {
if (current_level[i]->left != NULL) {
next_level.push_back(current_level[i]->left);
}
if (current_level[i]->right != NULL) {
next_level.push_back(current_level[i]->right);
}
std::cout << " " << current_level[i]->value;
}
current_level = next_level;
level++;
next_level.clear();
std::cout << std::endl;
}
}
int main() {
// creating a simple binary tree
// 1
// / \
// 2 3
// / \ / \
//4 5 6 7
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
// calling the breadth-first traversal function
breadth_first_traverse(root);
// cleaning up dynamically allocated memory
delete root->left->left;
delete root->left->right;
delete root->right->left;
delete root->right->right;
delete root->left;
delete root->right;
delete root;
return 0;
}

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -0,0 +1,53 @@
#include <iostream>
#include "ds_set_ptrs.h"
int main() {
// create a set of integers
ds_set<int> numbers;
// insert some values into the set
numbers.insert(10);
numbers.insert(5);
numbers.insert(88);
numbers.insert(20);
numbers.insert(49);
numbers.insert(15);
numbers.insert(36);
numbers.insert(5); // Duplicate value (won't be inserted)
// print the elements of the set
std::cout << "The elements in the set are:" << std::endl;
for(ds_set<int>::iterator itr = numbers.begin(); itr != numbers.end(); ++itr){
std::cout << *itr << " ";
}
std::cout << std::endl;
// check if a specific value exists in the set
int value = 15;
if (numbers.find(value) != numbers.end()) {
std::cout << value << " is found in the set." << std::endl;
} else {
std::cout << value << " is not found in the set." << std::endl;
}
// check if a specific value exists in the set
value = 66;
if (numbers.find(value) != numbers.end()) {
std::cout << value << " is found in the set." << std::endl;
} else {
std::cout << value << " is not found in the set." << std::endl;
}
numbers.erase(10);
numbers.erase(20);
numbers.erase(36);
// print the elements of the set
std::cout << "After erasing 10, 20 and 36, the elements in the set are:" << std::endl;
for(ds_set<int>::iterator itr = numbers.begin(); itr != numbers.end(); ++itr){
std::cout << *itr << " ";
}
std::cout << std::endl;
return 0;
}

View File

@@ -0,0 +1,206 @@
#include <utility> // for std::pair
#include <vector>
template <class T>
class TreeNode {
public:
T key;
TreeNode* left;
TreeNode* right;
// one way to allow implementation of iterator increment & decrement
TreeNode* parent;
// constructor
TreeNode(const T& k) {
key = k;
left = NULL;
right = NULL;
}
};
// -------------------------------------------------------------------
// TREE NODE ITERATOR CLASS
template <class T>
class tree_iterator {
public:
// default constructor
tree_iterator() = default; // including = default explicitly tells someone reading the code that
// you intend for the compiler to generate the default constructor.
// It makes your intent clearer.
// constructor
tree_iterator(std::vector<TreeNode<T>*> p) : ptrs(p) {}
// copy constructor
tree_iterator(const tree_iterator& other) : ptrs(other.ptrs) {}
// destructor
~tree_iterator() {}
// assignment operator
tree_iterator& operator=(const tree_iterator& other) { ptrs = other.ptrs; return *this; }
// operator* gives constant access to the value at the pointer
const T& operator*() const { return (ptrs.back())->key; }
// comparison operators are straightforward
bool operator== (const tree_iterator& other) { return ptrs == other.ptrs; }
bool operator!= (const tree_iterator& other) { return ptrs != other.ptrs; }
// increment & decrement operators
tree_iterator<T> & operator++() {
// prefix ++
if (ptrs.empty()) return *this; // end() reached
// ptrs.back() gives us the pointer points to the current node, i.e, that's where we are now.
TreeNode<T>* curr = ptrs.back();
// case 1: has right subtree
if (curr->right) {
curr = curr->right;
ptrs.push_back(curr);
// go as left as possible
while (curr->left) {
curr = curr->left;
ptrs.push_back(curr);
}
}
// case 2: no right subtree, go up
else {
TreeNode<T>* last = ptrs.back();
ptrs.pop_back();
// keep going up as long as I am (here I means last) the right child of my parent.
while (!ptrs.empty() && ptrs.back()->right == last) {
last = ptrs.back();
ptrs.pop_back();
}
// if ptrs empty now, we hit end()
}
// when we return, ptrs.back() should point to the destination node.
return *this;
}
tree_iterator<T> operator++(int) { tree_iterator<T> temp(*this); ++(*this); return temp; }
tree_iterator<T> & operator--() { /* implementation omitted */ }
tree_iterator<T> operator--(int) { tree_iterator<T> temp(*this); --(*this); return temp; }
private:
// representation
std::vector<TreeNode<T>*> ptrs; // store pointers to every node which is on the path from root to current node
};
// internally it's a binary search tree
template <class T>
class ds_set {
public:
ds_set(){
root = NULL;
m_size = 0;
}
typedef tree_iterator<T> iterator;
int size() { return m_size; }
iterator find(const T& key){
std::vector<TreeNode<T>*> ptrs;
return find(key, root, ptrs);
}
std::pair<iterator, bool> insert(const T& key){
std::pair<iterator, bool> temp;
std::vector<TreeNode<T>*> ptrs;
temp = insertHelper(key, root, ptrs);
if(temp.second == true){
++m_size;
}
return temp;
}
void erase(const T& key){
eraseHelper(key, root);
}
// ITERATORS
// return an iterator to the first (leftmost) node of the binary search tree,
// which can be found by traversing to the leftmost node starting from the root.
tree_iterator<T> begin() const {
std::vector<TreeNode<T>*> ptrs;
TreeNode<T>* p = root;
while (p) {
ptrs.push_back(p);
p = p->left; // go left
}
return tree_iterator<T>(ptrs);
}
tree_iterator<T> end() const { return tree_iterator<T>(); }
private:
TreeNode<T>* root;
int m_size;
iterator find(const T& key, TreeNode<T>* root, std::vector<TreeNode<T>*>& ptrs);
// as there are multiple templated classes involved, writing this function outside of the class definition may be too complicated.
// helper function to perform the insertion
std::pair<iterator, bool> insertHelper(const T& key, TreeNode<T>*& node, std::vector<TreeNode<T>*>& ptrs) {
// if node is nullptr, insert the key here
if (!node) {
node = new TreeNode<T>(key);
ptrs.push_back(node); // add the new node to the path
return {iterator(ptrs), true}; // return an iterator to the new node, and true for success
}
// if key is already present in the tree, no insertion occurs
if (key == node->key) {
return {iterator(ptrs), false}; // return an iterator to the existing node, and false for failure
}
// add the current node to the path
ptrs.push_back(node);
// recursively insert into the left or right subtree
if (key < node->key) {
return insertHelper(key, node->left, ptrs); // Traverse left
} else {
return insertHelper(key, node->right, ptrs); // Traverse right
}
}
// must pass root by reference here because we might change it.
void eraseHelper(const T& key, TreeNode<T>*& root){
if (root == NULL) return;
if (root->key == key) {
if (root->left == NULL && root->right == NULL){
// no child, just delete
delete root;
root = NULL;
} else if (root->left == NULL){
// doesn't have a left, let the right child take over
TreeNode<T>* temp = root;
root = root->right;
delete temp;
} else if (root->right == NULL){
// doesn't have a right, let the left child take over
TreeNode<T>* temp = root;
root = root->left;
delete temp;
} else {
// has both left and right
// let the leftmost node of the right subtree take over
TreeNode<T>* tmp = root->right;
while (tmp->left) {
tmp = tmp->left;
}
root->key = tmp->key;
// but then remove that leftmost node of the right subtree.
eraseHelper(tmp->key, root->right);
}
} else if (root->key > key) {
// search on the left subtree and erase
eraseHelper(key, root->left);
} else {
// search on the right subtree and erase
eraseHelper(key, root->right);
}
}
};
template <class T>
typename ds_set<T>::iterator ds_set<T>::find(const T& key, TreeNode<T>* root, std::vector<TreeNode<T>*>& ptrs){
// base case (if root doesn't even exist)
if(root == NULL){
return end();
}
// add current node to the path
ptrs.push_back(root);
// general case
if(key < root->key){
return find(key, root->left, ptrs);
}else if(key > root->key){
return find(key, root->right, ptrs);
}else{
return tree_iterator(ptrs);
}
}