Troubles with BST recursion (finding height of a tree in C++) - c++

int BST::getLength()
{
int leftHeight = 0;
int rightHeight = 0;
// Empty case
if (!prev && !dataInit)
return 0;
else
{
if (left)
{
leftHeight = left->getLength();
std::cout << "leftHeight: " << leftHeight;
std::cout << std::endl << std::endl;
}
if (right)
{
rightHeight = right->getLength();
std::cout << "rightHeight: " << rightHeight;
std::cout << std::endl << std::endl;
}
if (leftHeight > rightHeight)
return leftHeight + 1;
else
return rightHeight + 1;
}
}
This is a copied function from some website. I've been trying to write this function down on paper to understand the recursion but I can't seem to find myself comprehending. Specifically, I don't understand how leftHeight and rightHeight are incrementing by one if we're recursively calling it before we add 1.
Any help would be appreciated, thanks.

I am not completely sure about the structure of the rest of this code but I will hazard a guess here. It helps if we start thinking of base cases. For a binary tree, that would be the leaf nodes. For a leaf node, the height of its left or right children would be zero and the height of the entire tree including the leaf node is one.
We can then take a step back and consider a general node in the binary tree: the height of the tree starting at this node is max(leftSubTree, rightSubTree) + 1, where the +1 accounts for the current node.

Related

How to print a level of a binary search tree?

If we have say, a tree with a depth of 2:
6 <- depth = 0
/ \
/ \
4 9 <- depth = 1
/ \ \
3 5 10 <- depth = 2
And I only want to print the second level, so 3, 5, and 10 (in that order), how would I go about doing this? I'm using the code I wrote for my inorder traversal but I'm stuck on how to track depth of the tree and print when I'm at said depth.
void printLevelNodesHelper(MovieNode * curr, int level){ //helper function
int lvl = level; //store initial value of level
if(curr != NULL){
printLevelNodesHelper(curr->left, level+1);
if(level == lvl){
cout << "Movie: " << curr->title << " " << curr->rating << endl;
}
printLevelNodesHelper(curr->right, level+1);
}
}
void MovieTree::printLevelNodes(int k){ //k is the desired level
MovieNode * curr = root;
if(root == NULL){ //if the tree is empty exit it
return;
}
else if(k == 0){ //print the root's title
cout << "Movie: " << curr->title << " " << curr->rating << endl;
}
else{
printLevelNodesHelper(curr, k);
}
}
Here's the info for my struct and class
struct MovieNode{
int ranking;
string title;
int year;
float rating;
MovieNode* left = NULL;
MovieNode* right = NULL;
};
class MovieTree{
private:
MovieNode* root;
public:
MovieTree();
~MovieTree();
void printMovieInventory();
void addMovieNode(int ranking, std::string title, int year, float rating);
void findMovie(std::string title);
void queryMovies(float rating, int year);
void averageRating();
void printLevelNodes(int k);
};
Some issues:
As your initial call to printLevelNodesHelper gets the desired level as argument, it makes no sense to make recursive calls with level+1. Think about it: when you recur, you actually descend in the tree, coming closer to the desired level, so you should not increase the distance to that level, but decrease it. So you should pass level-1
In printLevelNodesHelper the if condition level == lvl is always going to be true, because neither of these local variables ever change value. As from the previous point we guarantee that eventually we will get a call with level equal to 0, we should check for level == 0 (and so you don't need the lvl variable).
Code:
void printLevelNodesHelper(MovieNode * curr, int level) {
if (curr != NULL) {
printLevelNodesHelper(curr->left, level - 1);
if (level == 0) {
cout << "Movie: " << curr->title << " " << curr->rating << endl;
}
printLevelNodesHelper(curr->right, level - 1);
}
}
With this change, the code for MovieTree::printLevelNodes does not need to deal with the boundary cases of root == NULL or k == 0. Both of these are well managed in the above helper function. On the other hand, you might want to add some protection against the infinite recursion that would occur if printLevelNodes is called with a negative value of k:
void MovieTree::printLevelNodes(int k) {
if (k >= 0) printLevelNodesHelper(root, k);
}

How can I traverse a Huffman Tree (via code) and print out the encodings for each letter?

I'd like to start with what I know about heaps and Huffman code.
For this project, we use a minimum heap. The top part of the upside-down tree (or root) holds the minimum element. Whenever something is added to the array, everything gets moved, so the root is always the minimum value element. Whenever an element is deleted, everything gets reconfigured with the top element holding the minimum once again. In class, we went over a (template) class called MaxHeap, which I converted into MinHeap without the template stuff.
My professor went over Huffman encoding, but I understood it best using this visual tool:
https://people.ok.ubc.ca/ylucet/DS/Huffman.html
The idea is to use a minimum heap as follows:
1. Delete two nodes
2. Create a new node with the deleted nodes as children. The frequency of this node is the summation of the two children frequencies.
3. Add this new node to the minimum heap
This process repeats until there is one node left in the heap (the root). Next, we find the encodings for each letter. To do this, travel down the tree with left movement being 0 and right movement being 1. Traveling right twice then left once would give 110 for the letter 'c' in my tree (image link can be found towards the bottom of my post).
Everything was going mostly fine until I needed to traverse from the root. I had no idea how to do this via code, so I tried googling the answers and found these two websites:
https://www.geeksforgeeks.org/huffman-coding-greedy-algo-3/
https://www.programiz.com/dsa/huffman-coding
I copied their function printCodes() into my code, but I didn't get see it work.
When I try manually going down the tree, I get two things. For example, I tried traveling left down the root and using cout to see the values. I expected to see 40, !, e, d; but when I tried I was getting gibberish number and characters (greek letters like theta, sigma, etc). It gets really weird because on line 207, yourRoot->left->freq gives me 40, but the same thing on the line 208 of code gives me a large number. When I traveled right, I got: Exception thrown: read access violation. yourRoot->right->right->letter was 0xCCCCCCCC.
To reiterate cout << yourRoot->left->freq << endl; will give me 40 the first time I call it, but the second time I get a random number. I expected the same output twice in a row. Am I supposed to keep a pointer or pointer-to-pointer to the address of yourRoot or something?
Another problem is in createHuffmanTree(), if I put return root; outside the while loop I get this error and the code doesn't run at all:
potentially uninitialized local pointer variable 'root' used
Both of these things were odd problems and I assume it has to do with the way I'm using & and * symbols. I tried using something like this:
MinHeap yourHeap = MinHeap(6);
node *item = newNode(30, 'f');
yourHeap.Insert(*item);
item = newNode(20, 'e');
yourHeap.Insert(*item);
item = newNode(20, 'd');
yourHeap.Insert(*item);
item = newNode(15, 'c');
yourHeap.Insert(*item);
item = newNode(10, 'b');
yourHeap.Insert(*item);
item = newNode(5, 'a');
yourHeap.Insert(*item);
delete item;
This works the same as the yourList[] code I have in main(), but I figured "keep it simple stupid" and avoid using pointers since I clearly have some issues with them.
I uploaded an output without any error causing code and a drawing of what I expect my tree to look like with the values I want to use (https://imgur.com/a/Vpx7Eif). If the link doesn't work, please let me know so I can fix it.
The code I have thus far is:
#include <iostream>
using namespace std;
#define MAX_TREE_HEIGHT 20
//exception is thrown if wrong input
class NoMem
{
public:
NoMem() { cout << "Heap is full\n"; }
};
class OutOfBounds
{
public:
OutOfBounds() { cout << "Heap is empty\n"; }
};
struct node
{
int freq;
char letter;
struct node *left, *right;
};
// initialize node with frequency and letter
node* newNode(int freq, char letter)
{
node *temp = new node;
temp->freq = freq;
temp->letter = letter;
temp->left = nullptr;
temp->right = nullptr;
return temp;
}
// initialize node using two nodes as children
node* newNode(node& a, node& b)
{
node *temp = new node;
temp->freq = a.freq + b.freq;
temp->letter = '!';
temp->left = &a;
temp->right = &b;
return temp;
}
class MinHeap {
public:
MinHeap(int MSize)
{
MaxSize = MSize;
heap = new node[MaxSize + 1];
Size = 0;
}
~MinHeap() { delete[] heap; }
MinHeap& Insert(node& x);
MinHeap& Delete(node& x);
void Display();
int Size;
private:
int MaxSize;
node *heap;
};
MinHeap& MinHeap::Insert(node& x)
{
if (Size == MaxSize) throw NoMem();
else
{
printf("Inserting '%c' with frequency of %d. ", x.letter, x.freq);
int i = ++Size;
while (i != 1 && x.freq < heap[i / 2].freq)
{
heap[i] = heap[i / 2];
i /= 2;
}
heap[i] = x;
Display();
return *this;
}
}
MinHeap& MinHeap::Delete(node& x)
{
if (Size == 0) throw OutOfBounds();
x.freq = heap[1].freq; // root has the smallest key
x.letter = heap[1].letter;
printf("Deleting '%c' with frequency of %d. ", x.letter, x.freq);
node y = heap[Size--]; // last element
int vacant = 1;
int child = 2; //make child = left child
while (child <= Size)
{
if (child < Size && heap[child].freq > heap[child + 1].freq) ++child;
// right child < left child
if (y.freq <= heap[child].freq) break;
heap[vacant] = heap[child]; // move smaller child
vacant = child; // new vacant
child = child * 2; // new child of vacant
}
heap[vacant] = y;
Display();
return *this;
}
void MinHeap::Display()
{
printf("Your heap contains: ");
for (int i = 1; i <= Size; i++)
printf("'%c' = %d, ", heap[i].letter, heap[i].freq);
printf("\n");
}
node* createHuffmanTree(MinHeap& yourHeap)
{
cout << "--- Creating Huffman Tree ---\n";
node left, right, *root;
while (yourHeap.Size > 1)
{
yourHeap.Delete(left);
yourHeap.Delete(right);
root = newNode(left, right);
cout << "-> New Node: freq = " << root->freq << ", letter = " << root->letter << ", left: " << root->left->letter << ", right: " << root->right->letter << endl;
yourHeap.Insert(*root);
if (yourHeap.Size < 2)
{
return root;
}
}
//return root; // potentially uninitialized local pointer variable 'root' used
}
void outputHuffmanCode(node* root, int arr[], int top)
{
// left movement is 0
if (root->left)
{
arr[top] = 0;
outputHuffmanCode(root->left, arr, top + 1);
}
// right movement is 1
if (root->right)
{
arr[top] = 1;
outputHuffmanCode(root->right, arr, top + 1);
}
// if reached leaf node, must print character as well
if (!(root->left) && !(root->right))
{
cout << "'" << root->letter << "' = ";
for (int i = 0; i < top; ++i)
cout << arr[i];
cout << endl;
}
}
int main()
{
node yourList[6];
yourList[0].freq = 5;
yourList[0].letter = 'a';
yourList[1].freq = 10;
yourList[1].letter = 'b';
yourList[2].freq = 15;
yourList[2].letter = 'c';
yourList[3].freq = 20;
yourList[3].letter = 'd';
yourList[4].freq = 20;
yourList[4].letter = 'e';
yourList[5].freq = 30;
yourList[5].letter = 'f';
cout << "Here is your list: ";
for (int i = 0; i < 6; i++)
{
cout << "'" << yourList[i].letter << "' = " << yourList[i].freq;
if (i < 5) cout << ", ";
} cout << endl;
MinHeap yourHeap(6);
yourHeap.Insert(yourList[5]);
yourHeap.Insert(yourList[4]);
yourHeap.Insert(yourList[3]);
yourHeap.Insert(yourList[2]);
yourHeap.Insert(yourList[1]);
yourHeap.Insert(yourList[0]);
/*
MinHeap yourHeap = MinHeap(6);
node *item = newNode(30, 'f');
yourHeap.Insert(*item);
item = newNode(20, 'e');
yourHeap.Insert(*item);
item = newNode(20, 'd');
yourHeap.Insert(*item);
item = newNode(15, 'c');
yourHeap.Insert(*item);
item = newNode(10, 'b');
yourHeap.Insert(*item);
item = newNode(5, 'a');
yourHeap.Insert(*item);
delete item;
*/
node *yourRoot = newNode(0, NULL);
yourRoot = createHuffmanTree(yourHeap);
// same cout twice in a row, different results
//cout << yourRoot->left->freq << endl;
//cout << yourRoot->left->freq << endl;
cout << "L0 Root: freq = " << yourRoot->freq << ", letter = " << yourRoot->letter << ", left freq: " << yourRoot->left->freq << ", right freq: " << yourRoot->right->freq << endl;
cout << "L11 Left: freq = " << yourRoot->left->freq << ", letter = " << yourRoot->left->letter << ", left: " << yourRoot->left->left->letter << ", right: " << yourRoot->left->right->letter << endl;
//cout << "R11 Left: freq = " << yourRoot->right->freq << ", letter = " << yourRoot->right->letter << ", left: \n";
//<< yourRoot->right->left->letter << ", right: " << yourRoot->right->right->letter << endl;
//int arr[MAX_TREE_HEIGHT], top = 0;
//outputHuffmanCode(yourRoot, arr, top);
system("pause");
return 0;
}
I'd like to thank whoever reads and replies to this post in advance. I think I've given as much information as I could. If I did anything that's against community rules, please let me know so I can fix my mistake(s).
In your createHuffmanTree Function, you create the node's left and right...
with root = newNode(left, right); you let the left/right member of your struct point to the address of the (temporary) node you've created in createHuffmanTree (that means in
node* newNode(node& a, node& b)
the address of a and b is always the same..
and the node goes out of scope after leaving the createHuffmanTree function - i think this causes your problem. You know what I mean?

Solving 8-Puzzle in C++ with A* results in endless loop

I'm currently trying to solve the 8-Puzzle with the A* search algorithm, but my program gets stuck in an endless loop.
My main searching loop is:
std::vector<Field> Search::AStar(Field &start, Field &goal){
std::cout << "Calculating..." << std::endl;
std::unordered_map<Field, Field> explored;
std::vector<Field> searched;
if (Puzzle::finished(start))
return MakePath(start, start);
std::priority_queue<Field, std::vector<Field>, std::greater<Field>> frontier;
frontier.push(start);
Field current;
Field child;
size_t i = 0;
while (!frontier.empty())
{
current = frontier.top();
frontier.pop();
if (++i > 500)
{
std::cout << "Iteration Error" << std::endl;
return searched;
}
searched.push_back(current);
for (Direction d : Puzzle::Actions(current))
{
child = Puzzle::Action(d, current);
if (Puzzle::finished(child))
{
std::cout << "Found goal!" << std::endl;
return MakePath(explored[child], start);
}
child.CostG = current.CostG + 1; // Make a step
if (!isIn(child, explored) || child.CostG < explored[child].CostG)
{
child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
child.CostF = child.CostG + child.CostH; // Calculate final costs
frontier.push(child);
explored[child] = child;
explored[child].setParent(&explored[current]);
}
}
}
std::cout << "Error: frontier Empty" << std::endl;
return searched;
}
The vector "searched" is just so that I can see what A* does, and I will delete it as soon as the algorithm works.
The CostG stands for the number of steps done until this point, the CostH are the estimated minimum (heuristic) costs to the "goal" and the CostF are those two combined.
The index of the Field::Boxes vector is the number of the field, and every element contains the position.
My Heuristic function looks like this:
inline int Heuristic(Field &goal)
{
size_t d = 0;
for (size_t i = 0; i < Boxes.size(); i++)
{
d += (std::abs(static_cast<int>(Boxes[i].x) - static_cast<int>(goal.Boxes[i].x))
+ std::abs(static_cast<int>(Boxes[i].y) - static_cast<int>(goal.Boxes[i].y)));
}
return d;
}
For better readability and stuff, the code also is on Github. However, to execute it, you need SFML in your Visual Studio include direction.
Every help is appreciated!
Edit 1:
You now no longer need SFML to executed & debug the program! I commited the changes to github, the link is the same.
The problem is that although you remove the current node from your frontier, you never added it to the explored set, i.e. you never close it. The following code should work. My revisions closely follow Wikipedia's A* Pseudocode.
I also recommend you test your algorithm with the trivial heuristic (the one that returns zero for all values) on a simple puzzle to verify that your algorithm is implemented correctly. (See this answer for a brief explanation of this technique.)
while (!frontier.empty())
{
current = frontier.top();
frontier.pop();
if (++i > 500)
{
std::cout << "Iteration Error" << std::endl;
return searched;
}
// Check for goal here
if (Puzzle::finished(current)
{
std::cout << "Found goal!" << std::endl;
return MakePath(explored[current], start);
}
explored[current] = current; //close the current node
searched.push_back(current);
for (Direction d : Puzzle::Actions(current))
{
child = Puzzle::Action(d, current);
if (isIn(child,explored))
{
continue; //ignore the neighbor which is already evaluated
}
child.CostG = current.CostG + 1; // Make a step
if (!isIn(child, frontier)) //discovered a new node
{
frontier.push(child);
}
else if (child.CostG >= explored[child].CostG)
{
continue; //this is not a better path
{
//the path is best until now. Record it!
child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
child.CostF = child.CostG + child.CostH; // Calculate final costs
//frontier.push(child); moved up to earlier point in code
explored[child] = child;
explored[child].setParent(&explored[current]);
}
}

Depth first search (C++)

I've created a class that contains a vector of Linked Lists. Each Linked List represents a vertice in my graph. The Nodes connected to my linked lists are considered the edges between these vertices. I'm trying to create a DFS function for my graph, but am having trouble with setting the colors of my vertices. I realize there are a lot of problems with my code, but i'm trying to solve one in particular. My DFSit() function ends up in an infinite loop because the color attribute for my list isn't actually getting set to "gray". Any idea why this would be?
void Graph::DFS()
{
int i = 0;
while (i != myvector.size())
{
DFSit(myvector[i], myvector[i].val);
myvector[i].color = "black";
i++;
}
}
void Graph::DFSit(AdjList x, int root)
{
if (x.color == "white")
{
cout << "tree edge ( " << root << "," << x.val << ") " << endl;
}
if (x.color == "gray")
{
cout << "Back Edge ( " << root << "," << x.val << ") " << endl;
return;
}
x.color = "gray";
AdjNode *temp = new AdjNode();
temp = x.front;
int i = 0;
int value;
while (temp != NULL)
{
value = temp->getValue();
while (i != myvector.size())
{
if (value == myvector[i].val)
{
DFSit(myvector[i], root);
}
i++;
}
temp = temp->next;
}
}
Normaly, the proper implementation of the DFS rutine is made with a stack, but this could work also.
I think that you are coloring the node AdjList x and this coloring is not save because you are passing it by val and not by ref.
try changing void Graph::DFSit(AdjList x, int root) into void Graph::DFSit(AdjList& x, int root)

c++ trying to find the distance between 2 nodes

I am currently working on a function that has 1 helper function, the main function takes in 2 strings and searches for the first one (which becomes a reference as if it was m_root) and a second one to be searched in the tree. once they are searched, my helper function is supposed to search for the 2nd city and count the distance it had to travel as if a truck was going towards that city.
int Stree::distance(string origin_city, string destination_city)
{
int total_distance = 0;
Node *new_root = m_root;
new_root = find_node(m_root, origin_city);
total_distance = get_distance(new_root, total_distance, destination_city);
return total_distance;
}
int Stree::get_distance(Node* cur, int distance, string destination)
{
Node *tmp = cur;
if(cur == NULL)
return 0;
if(cur->m_city == destination || tmp->m_city == destination)
{
//cout << distance + cur->m_parent_distance << endl;
return distance += cur->m_parent_distance;
}
if(tmp->m_left != NULL)
{
//cout << "checking left" << endl;
tmp = cur->m_left;
return get_distance(cur->m_left, distance, destination) ;
}
else
{
//cout << "checking right" << endl;
return get_distance(cur->m_right, distance, destination);
}
}
In a cursory glance, I don't see anywhere that you modify or increment distance, whether it be the distance variable or something like:
return 1 + get_distance(cur->m_right, distance, destination);
So I would make sure that in an algorithmic sense, each step walked is counted, otherwise it will certainly return 0 every time.