Compare commits
41 Commits
54016a2693
...
48d8b8fcfd
| Author | SHA1 | Date | |
|---|---|---|---|
| 48d8b8fcfd | |||
|
|
eaa3021d47 | ||
|
|
8e9b9675bf | ||
|
|
cc162dff6f | ||
|
|
09745ed253 | ||
|
|
7750b9bba2 | ||
|
|
1e9e14e83c | ||
|
|
73b283c87f | ||
|
|
981bb8394b | ||
|
|
f8f4250479 | ||
|
|
dafa3d68e8 | ||
|
|
1dd3a91c3c | ||
|
|
68bdc8d087 | ||
|
|
7443ce2e1a | ||
|
|
4b1246b9a1 | ||
|
|
12bbbf410f | ||
|
|
3917bbbdc1 | ||
|
|
ec5739add4 | ||
|
|
e783fa7d83 | ||
|
|
1556940408 | ||
|
|
eb67680841 | ||
|
|
a845f0752c | ||
|
|
610455146e | ||
|
|
e005a62828 | ||
|
|
ba74c7efbe | ||
|
|
6198e34b84 | ||
|
|
c57da3131c | ||
|
|
d833d16444 | ||
|
|
d6e4a2cfae | ||
|
|
c9d4888ed6 | ||
|
|
9feed1f407 | ||
|
|
be8d649ead | ||
|
|
230751b5b8 | ||
|
|
a9ced246db | ||
|
|
956d3892da | ||
|
|
fb81b68821 | ||
|
|
640cfc6c08 | ||
|
|
97034d0b94 | ||
|
|
09817c3736 | ||
|
|
bed6b5cbc1 | ||
|
|
66d94e8f96 |
14
.vscode/launch.json
vendored
@@ -104,6 +104,20 @@
|
|||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
"miDebuggerPath": "/usr/bin/gdb",
|
"miDebuggerPath": "/usr/bin/gdb",
|
||||||
"preLaunchTask": "C/C++: g++ build active file"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ drawNode(650, 100, '5');
|
|||||||
layer.add(line1);
|
layer.add(line1);
|
||||||
layer.add(line2);
|
layer.add(line2);
|
||||||
drawNode(500, 200, '3');
|
drawNode(500, 200, '3');
|
||||||
drawNode(800, 200, '6');
|
drawNode(800, 200, '8');
|
||||||
layer.add(line3);
|
layer.add(line3);
|
||||||
layer.add(line4);
|
layer.add(line4);
|
||||||
drawNode(350, 300, '2');
|
drawNode(350, 300, '2');
|
||||||
@@ -225,7 +225,7 @@ drawNode(700, 300, '7');
|
|||||||
layer.add(line6);
|
layer.add(line6);
|
||||||
layer.add(line7);
|
layer.add(line7);
|
||||||
drawNode(200, 400, '1');
|
drawNode(200, 400, '1');
|
||||||
drawNode(800, 400, '8');
|
drawNode(800, 400, '7.5');
|
||||||
layer.add(line8);
|
layer.add(line8);
|
||||||
line8.hide();
|
line8.hide();
|
||||||
layer.draw();
|
layer.draw();
|
||||||
@@ -365,19 +365,44 @@ function nextstep() {
|
|||||||
stage.find('#nullptr').show();
|
stage.find('#nullptr').show();
|
||||||
layer.draw();
|
layer.draw();
|
||||||
}else if(key == 5){
|
}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();
|
line5.hide();
|
||||||
stage.find('#node_'+key).hide();
|
stage.find('#node_'+key).hide();
|
||||||
stage.find('#node_text_'+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).x(800);
|
||||||
stage.find('#node_'+7).y(200);
|
stage.find('#node_'+7).y(200);
|
||||||
stage.find('#node_text_'+7).x(795);
|
stage.find('#node_text_'+7).x(795);
|
||||||
stage.find('#node_text_'+7).y(190);
|
stage.find('#node_text_'+7).y(190);
|
||||||
stage.find('#node_'+8).x(950);
|
stage.find('#node_'+7.5).x(950);
|
||||||
stage.find('#node_'+8).y(300);
|
stage.find('#node_'+7.5).y(300);
|
||||||
stage.find('#node_text_'+8).x(945);
|
stage.find('#node_text_'+7.5).x(945);
|
||||||
stage.find('#node_text_'+8).y(290);
|
stage.find('#node_text_'+7.5).y(290);
|
||||||
line7.hide();
|
line7.hide();
|
||||||
line8.show();
|
line8.show();
|
||||||
hidden_6=1;
|
hidden_6=1;
|
||||||
@@ -386,13 +411,14 @@ function nextstep() {
|
|||||||
line7.hide();
|
line7.hide();
|
||||||
stage.find('#node_'+key).hide();
|
stage.find('#node_'+key).hide();
|
||||||
stage.find('#node_text_'+key).hide();
|
stage.find('#node_text_'+key).hide();
|
||||||
stage.find('#node_'+8).x(700);
|
// move 7.5 to 7
|
||||||
stage.find('#node_'+8).y(300);
|
stage.find('#node_'+7.5).x(700);
|
||||||
stage.find('#node_text_'+8).x(695);
|
stage.find('#node_'+7.5).y(300);
|
||||||
stage.find('#node_text_'+8).y(290);
|
stage.find('#node_text_'+7.5).x(695);
|
||||||
|
stage.find('#node_text_'+7.5).y(290);
|
||||||
hidden_7=1;
|
hidden_7=1;
|
||||||
layer.draw();
|
layer.draw();
|
||||||
}else if(key == 8){
|
}else if(key == 7.5){
|
||||||
// hide this node, and show a NULL pointer.
|
// hide this node, and show a NULL pointer.
|
||||||
stage.find('#node_'+key).hide();
|
stage.find('#node_'+key).hide();
|
||||||
stage.find('#node_text_'+key).hide();
|
stage.find('#node_text_'+key).hide();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h1>Recursive Program: Delete a Node in a Binary Search Tree</h1>
|
<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>
|
<label>delete node</label> <input type="text" id="textIn"><button onclick="start()">Start</button>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -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).
|
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 <filesystem> 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 <filesystem> or <dirent>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
|
## 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)
|
- 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)
|
- DATA REPRESENTATION (7 pts)
|
||||||
- Uses data structures which have not been covered in this class. (-7)
|
- Uses data structures which have not been covered in this class. (-7)
|
||||||
- Uses filesystem library (i.e., #include <filesystem> ). (-7)
|
- Uses filesystem library (i.e., #include <filesystem> or #include <dirent>). (-7)
|
||||||
- Neither std::map nor std::set is used. (-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)
|
- 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)
|
- RECURSION (3 pts)
|
||||||
|
|||||||
@@ -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.
|
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: don’t 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 don’t forget to comment your code! Use the provided template [README.txt](./README.txt) file for notes you want the grader to read.
|
Use good coding style when you design and implement your program. Organize your program into functions: don’t 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 don’t 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.
|
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
|
## 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.
|
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
|
## Rubric
|
||||||
|
|
||||||
17 pts
|
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)
|
- 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 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)
|
- 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)
|
- DATA REPRESENTATION (6 pts)
|
||||||
- Does not use tree data structures to store the comments. (-6)
|
- Does not use tree data structures to store the comments. (-6)
|
||||||
- RECURSION (2 pts)
|
- RECURSION (2 pts)
|
||||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
@@ -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": "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": "@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": "@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": "@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": "@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 ?"}
|
{"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": "@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": "@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": "@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", "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": "KLLALNGGA"}
|
{"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": "@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": "@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😮"}
|
{"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😮"}
|
||||||
@@ -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": "@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 don’t say that I don’t know what I’m talking about but this team would beat 2008 Man utd"}
|
{"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 don’t say that I don’t know what I’m 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": "@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": "@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": "@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"}
|
{"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": "@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": "@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": "@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": "@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": "@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": "@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": "@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": "@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": "@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 wasn’t 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 wasn’t 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": "@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": "@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 🥲"}
|
{"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
@@ -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
48
labs/maps/checkpoint2.cpp
Normal 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
@@ -0,0 +1 @@
|
|||||||
|
19 83 -12 83 65 19 45 -12 45 19 45
|
||||||
BIN
labs/maps/phonebook2
Executable file
42
labs/maps/phonebook2.cpp
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,14 +1,22 @@
|
|||||||
# Lab 10 — Trees, Binary Trees, & Binary Search Trees
|
# Lab 8 — Trees, Binary Trees, & Binary Search Trees
|
||||||
|
|
||||||
## Checkpoint 1
|
## Checkpoint 1
|
||||||
|
|
||||||
*estimate: 20-30 minutes*
|
*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 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 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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?
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ public:
|
|||||||
// comparions operators are straightforward
|
// comparions operators are straightforward
|
||||||
bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; }
|
bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; }
|
||||||
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:
|
private:
|
||||||
// representation
|
// representation
|
||||||
@@ -93,7 +92,6 @@ private:
|
|||||||
|
|
||||||
// PRIVATE HELPER FUNCTIONS
|
// PRIVATE HELPER FUNCTIONS
|
||||||
TreeNode<T>* copy_tree(TreeNode<T>* old_root) {
|
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) {
|
iterator find(const T& key_value, TreeNode<T>* p) {
|
||||||
if (!p) return iterator(NULL);
|
if (!p) return iterator(NULL);
|
||||||
@@ -132,7 +130,7 @@ private:
|
|||||||
return std::pair<iterator,bool>(iterator(p), false);
|
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 {
|
void print_in_order(std::ostream& ostr, const TreeNode<T>* p) const {
|
||||||
if (p) {
|
if (p) {
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -1,28 +1,20 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "ds_set_starter.h"
|
#include "ds_set_starter.h"
|
||||||
// #include <set>
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// create a set of integers
|
// create a set of integers
|
||||||
std::set<int> numbers;
|
ds_set<int> numbers;
|
||||||
|
|
||||||
// insert some values into the set
|
// insert some values into the set
|
||||||
numbers.insert(10);
|
numbers.insert(10);
|
||||||
numbers.insert(5);
|
numbers.insert(5);
|
||||||
numbers.insert(20);
|
numbers.insert(20);
|
||||||
numbers.insert(15);
|
numbers.insert(15);
|
||||||
numbers.insert(5); // Duplicate value (won't be inserted)
|
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
|
// check if a specific value exists in the set
|
||||||
int value = 15;
|
int value = 15;
|
||||||
if (numbers.find(value) != numbers.end()) {
|
if (numbers.find(value) == true) {
|
||||||
std::cout << value << " is found in the set." << std::endl;
|
std::cout << value << " is found in the set." << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::cout << value << " is not found in the set." << std::endl;
|
std::cout << value << " is not found in the set." << std::endl;
|
||||||
|
|||||||
31
lectures/18_trees_I/set_main.cpp
Normal 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;
|
||||||
|
}
|
||||||
@@ -3,20 +3,17 @@
|
|||||||
## Review from Lecture 18
|
## Review from Lecture 18
|
||||||
|
|
||||||
- Binary Trees, Binary Search Trees, & Balanced Trees
|
- 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.
|
- Finding the smallest element in a BST.
|
||||||
- Overview of the ds set implementation: begin and find. (leetcode 700)
|
|
||||||
|
|
||||||
## Today’s Lecture
|
## Today’s Lecture
|
||||||
|
|
||||||
- Warmup / Review: destroy_tree
|
- Warmup / Review: destroy_tree
|
||||||
- A very important ds set operation insert
|
|
||||||
- In-order, pre-order, and post-order traversal
|
- In-order, pre-order, and post-order traversal
|
||||||
- Finding the in-order successor of a binary tree node, tree iterator increment
|
- Finding the in-order successor of a binary tree node, tree iterator increment
|
||||||
|
|
||||||
## 19.1 Warmup Exercise
|
## 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
|
## 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 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, we’ll need to rewrite the insert and erase member functions to
|
- If we choose the parent pointer method, we’ll 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.
|
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!
|
Be sure to draw a picture to help you understand!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Exercise: [method 2] Write a fragment of code that given a tree iterator containing a pointer to the node and a
|
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).
|
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.
|
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?
|
<!--  -->
|
||||||
|
|
||||||
|
<!-- Exercise: What are the advantages & disadvantages of each method? -->
|
||||||
|
|
||||||
## 19.5 Limitations of Our BST Implementation
|
## 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 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).
|
- 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
|
- 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
|
## 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
|
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 ≥keyk−1.
|
the rightmost child which has only keys ≥keyk−1.
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|||||||
132
lectures/19_trees_II/ds_set.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
42
lectures/19_trees_II/ds_set_main.cpp
Normal 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;
|
||||||
|
}
|
||||||
BIN
lectures/19_trees_II/general_tree.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
79
lectures/19_trees_II/general_tree_post_order.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
76
lectures/19_trees_II/general_tree_pre_order.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,21 +6,18 @@ Review from Lecture 18 & 19
|
|||||||
- In-order, pre-order, and post-order traversal;
|
- 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
|
- Iterator implementation. Finding the in order successor to a node: add parent pointers or add a list/vector/stack
|
||||||
of pointers to the iterator.
|
of pointers to the iterator.
|
||||||
- B+ Tree Overview
|
<!-- - B+ Tree Overview -->
|
||||||
|
|
||||||
## Today’s Lecture
|
## Today’s Lecture
|
||||||
|
|
||||||
- Breadth-first and depth-first tree search
|
- Second approach of iterator increement/decrement operator
|
||||||
- Increement/decrement operator
|
|
||||||
- Tree height, longest-shortest paths, breadth-first search
|
|
||||||
- Last piece of ds_set: removing an item, erase
|
- Last piece of ds_set: removing an item, erase
|
||||||
- Erase with parent pointers, increment operation on iterators
|
- Breadth-first and depth-first tree search
|
||||||
- Limitations of our ds set implementation
|
|
||||||
|
|
||||||
## 20.1 ds_set Warmup/Review Exercises
|
## 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
|
- 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?
|
only one valid memory layout for this data as a ds_set? Why?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -39,56 +36,13 @@ only one valid memory layout for this data as a ds set? Why?
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 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.
|
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 depth-first search, we greedily follow links down into the tree, and don’t 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.
|
<!-- ## 20.5 Height and Height Calculation Algorithm
|
||||||
- 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
|
|
||||||
|
|
||||||
- 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.
|
- 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 let’s write a function to instead calculate the shortest path to a NULL child pointer.
|
- Now let’s write a function to instead calculate the shortest path to a NULL child pointer.
|
||||||
|
|
||||||
@@ -171,8 +125,9 @@ void shortest_path_breadth(Node* root)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
## 20.6 Erase
|
## 20.3 Erase
|
||||||
|
|
||||||
- First we need to find the node to remove. Once it is found,
|
- 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.
|
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.
|
- 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.
|
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
|
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.
|
tree, give an erase ordering that yields an unbalanced tree.
|
||||||
@@ -201,60 +191,8 @@ tree, give an erase ordering that yields an unbalanced tree.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
```cpp
|
<!--
|
||||||
Code for function ERASE built in class so remember it has not been executed yet and may require some fixes here and there.
|
## 20.8 Erase (now with parent pointers)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
- If we choose to use parent pointers, we need to add to the Node representation, and re-implement several ds_set member functions.
|
- 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.
|
- Exercise: Study the new version of insert, with parent pointers.
|
||||||
@@ -266,4 +204,67 @@ return 0;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
## 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 don’t 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.
|
||||||
|
|
||||||
|
|||||||
78
lectures/20_trees_III/bfs_main.cpp
Normal 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;
|
||||||
|
}
|
||||||
72
lectures/20_trees_III/bfs_main_vector.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
53
lectures/20_trees_III/ds_set_main.cpp
Normal 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;
|
||||||
|
}
|
||||||
206
lectures/20_trees_III/ds_set_ptrs.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||