I'm trying to create a function that counts the number of nodes inserted in a BST. I am not sure why I'm getting bad access. I would really appreciate your help!
I am trying to implement totl, which counts the number of words in a tree, including the duplicated words that weren't added to the tree (but incremented m_count)
However, I am getting bad access for this:
int totl(T * curr) const
{
if(root==nullptr)return 0;
else
{
return root->m_count + totl(root->m_left) + totl(root->m_right);
}
}
The code should have used curr not root in the recursive function, which then is called as totl(root) in main.
Related
I am trying to find a way to output the amount of most left nodes found in a path.
For example:
The max nodes in this Binary Search Tree would be 2 (Goes from 5 ->3->1 and excluding the root).
What is the best way to approach this?
I have seen this thread which is fairly similar to what I am trying to achieve.
Count number of left nodes in BST
but there is like one line in the code that I don't understand.
count += countLeftNodes(overallRoot.left, count++);
overallRoot.left
My guess is that it calls a function on the object, but I can't figure out what goes into that function and what it would return.
Any answers to these two questions would be appreciated.
The answer you linked shows how to traverse the tree, but you need a different algorithm to get your count, since as you have noted, that question is trying to solve a slightly different problem.
At any given point in the traversal, you will have the current left count: this will be passed down the tree as a second parameter to countLeftNodes(). That starts with zero at the root, and is increased by one whenever you go into the left child of a node, but is set to zero when you enter the right node.
Then for both the left and right traversals, you set the left count to the greater of its current value, and the return from the recursive call to countLeftNodes(). And then this final value is what you return from countLeftNodes()
Here's a shot at the algorithm #dgnuff illustrated:
void maxLeftNodesInPath(Node *root, int count, int *best) {
if (root) {
maxLeftNodesInPath(root->left, ++count, best);
maxLeftNodesInPath(root->right, 0, best);
}
else if (count > *best) {
*best = count - 1;
}
}
The explanation is pretty much the same: keep accumulating on a count while traversing left, reset when moving to a right child, and if at a leaf, update the best.
I am implementing a Depth First Search on a graph in C++. Given a starting vertex, the algorithm should perform DFS until a goal node is found (i.e. a node with goal set to true), and return the path taken. I am trying to do this recursively, here is my code:
vector<char>* dfs(graph g, node* s){
static vector<char> path;
s->set_visited();
path.push_back(s->get_tag()); //Adds node to path
if(s->is_goal()){
g.set_all_visited();
}
else{
for(int i=0; i<(s->get_no_edges()); i++){
if(!(s->get_edge(i)->get_dest()->is_visited())) //If it is unvisited, apply recursion
dfs(g, s->get_edge(i)->get_dest());
}
}
return &path;
}
I am aware that the resulting path will just list the nodes in the order they were visited by the DFS, as opposed to an actual path from the start to a goal node.
The problem is that the function continues to print nodes even after a goal node is found. To avoid this, I set all nodes in the graph g to visited using set_all_visited(), and checked in the else part whether a node was visited or not before proceeding, but this does not seem to be working. When I performed dry runs, the function kept on visiting all the edges of a node in the for loop even after a goal node was found, and I do not know how I can stop this from happening.
You're passing g by value instead of by reference. This means that whenever you found a goal node and are coming back from a recursive call, that instance of g still has its nodes set as unvisited. That's why the repetition occurs.
I know your primary question is answered, still I would give few suggestions:
1) Don't use static vector, you can't reuse the function. You can instead create a vector where you're expecting the path and pass pointer to the vector.
2) To make sure you don't have all visited nodes in path, you can return a bool from dfs function to denote if there is a path to destination. You can also avoid passing graph object this way.
With those changes your code will become:
bool dfs(node* s, vector<char>* path){
s->set_visited();
if(s->is_goal()){
path.push_back(s->get_tag());
return true;
}
else{
for(int i=0; i<(s->get_no_edges()); i++){
if(!(s->get_edge(i)->get_dest()->is_visited())) //If it is unvisited, apply recursion
if(dfs(s->get_edge(i)->get_dest(), path)) {
path.push_back(s->get_tag());
return true;
}
}
}
return false;
}
This will return reverse path, ie path from destination to source, there is std::reverse.
If you do a BFS, you'll get shortest path instead of some random path, assuming the edges are of equal weight.
I guess my Problem is really easy, but I tried to fix it for hours now, and I don't seem to get it. I have an ast tree (created with boost-library) and im iterating through it with recursion. I'm saving all Nodes in a List of NodeDescriptions, that contain the number of the actual node, the name of the actual Node, and node that is the parent node to the actual node. However, my parent node always has the wrong number. I guess I'm doing something wrong with the scope of my variables, passing it the wrong way, or anything like this. I would be glad if someone could help me:
void convert_to_parsetree(BOOST_SPIRIT_NAMESPACE::tree_match<iterator_t>::const_tree_iterator parse_node, int calNode) {
int remNum = calNode;
std::string node_value(parse_node->value.begin(), parse_node->value.end());
//First Element: Node-Counter, Second Element, Name of Node, Third Element: Parent Node Number
myList.push_back(NodeDescription(counter++, node_value, remNum));
if (parse_node->children.size() > 0) {
if (parse_node->children.size() > 1) {
//std::string value(parse_node->children[0].value.begin(), parse_node->children[0].value.end());
//std::string value2(parse_node->children[1].value.begin(), parse_node->children[1].value.end());
BOOST_SPIRIT_NAMESPACE::tree_match<iterator_t>::const_tree_iterator children_it = parse_node->children.begin();
for (int i = 0; i < parse_node->children.size(); ++i) {
convert_to_parsetree(children_it, counter);
children_it++;
}
} else {
convert_to_parsetree(parse_node->children.begin(), counter);
}
}
}
Quite simple, but somehow it doesn't work. Thanks in Advance and kind regards.
The problem is that in your recursive call, you are passing the value in the global variable counter as the second parameter. However, your recursive function uses the second parameter as the "Parent Node Number" (since it is saved in remNum), and the global counter gets incremented. This means the for loop that iterates over the children with the recursive calls will be passing in a different counter value at each iteration, even though each recursive call is supposed to be from the same "Parent".
The current level of recursion should remember the current counter value as its node number before it is incremented, and this remembered value is what should be passed into each iteration of the for loop.
In the fixed version of the code below, I simplified your function to improve readability.
typedef BOOST_SPIRIT_NAMESPACE::tree_match<iterator_t>::const_tree_iterator
MyTreeIterator;
void convert_to_parsetree (MyTreeIterator parse_node, int parent_number) {
int node_number = counter++;
std::string node_name(parse_node->value.begin(), parse_node->value.end());
myList.push_back(NodeDescription(node_number, node_name, parent_number));
for (MyTreeIterator children_it = parse_node->children.begin();
children_it != parse_node->children.end();
++children_it) {
convert_to_parsetree(children_it, node_number);
}
}
I'm trying to create a function that finds the average of some data within the nodes of a tree. The problem is, every node contains two pieces of data and unlike other BSTs, the primary data from which it is built is a string. Finding the average of number-based elements in a tree isn't an issue for me, but since each node contains a string (a person's name) and a seemingly random number (the weight of said person), the tree is actually in complete disarray, and I have no idea how to deal with it.
Here is my node so you see what I mean:
struct Node {
string name;
double weight;
Node* leftChild;
Node* rightChild;
};
Node* root;
Here's the function during one of its many stages:
// This isn't what I'm actually using so don't jump to conclusions
double nameTree::averageWeight(double total, double total, int count) const
{
if (parent != NULL)
{ //nonsense, nonsense
averageWeight(parent->leftChild, total, count);
averageWeight(parent->rightChild, total, count);
count++;
total = total + parent->weight;
return total;
}
return (total / count);
}
In an effort to traverse the tree, I tried some recursion but every time I manage to count and total everything, something gets screwey and it ends up doing return(total/count) each time. I've also tried an array implementation by traversing the tree and adding the weights to the array, but that didn't work because the returns and recursion interfered, or something.
And just because I know someone is going to ask, yes, this is for a school assignment. However, this is one out of like, 18 functions in a class so it's not like I'm asking anyone to do this for me. I've been on this one function for hours now and I've been up all night and my brain hurts so any help would be vastly appreciated!
You could try something like:
//total number of tree nodes
static int count=0;
// Calculate the total sum of the weights in the tree
double nameTree::calculateWeight(Node *parent)
{
double total=0;
if (parent != NULL)
{
//nonsense, nonsense
//Calculate total weight for left sub-tree
total+=calculateWeight(parent->leftChild);
//Calculate weight for right sub-tree
total+=calculateWeight(parent->rightChild);
//add current node weight
total+=parent->weight;
}
count++;
//if it is a leaf it will return 0
return total;
}
double averageWeight()
{
double weightSum;
weightSum=calculateWeight();
if(count!=0)
return (weightSum/count);
else
{
cout<<"The tree is empty";
return 0;
}
}
I don't have a compiler here but I believe it works.
To calculate the average you need two numbers: the total value and the number of elements in the set. You need to provide a function (recursive is probably the simplest) that will walk the tree and either return a pair<double,int> with those values or else modify some argument passed as reference to store the two values.
As of your code, averageWeight returns a double, but when you call it recursively you are ignoring (discarding) the result. The count argument is passed by copy, which means that the modifications applied in the recursive calls will not be visible by the caller (which then does not know how much parent->weight should weight towards the result.
This should be enough to get you started.
I'm having a problem with a pointer and can't get around it..
In a HashTable implementation, I have a list of ordered nodes in each bucket.The problem I have It's in the insert function, in the comparision to see if the next node is greater than the current node(in order to inserted in that position if it is) and keep the order.
You might find this hash implementation strange, but I need to be able to do tons of lookups(but sometimes also very few) and count the number of repetitions if It's already inserted (so I need fasts lookups, thus the Hash , I've thought about self-balanced trees as AVL or R-B trees, but I don't know them so I went with the solution I knew how to implement...are they faster for this type of problem?),but I also need to retrieve them by order when I've finished.
Before I had a simple list and I'd retrieve the array, then do a QuickSort, but I think I might be able to improve things by keeping the lists ordered.
What I have to map It's a 27 bit unsigned int(most exactly 3 9 bits numbers, but I convert them to a 27 bit number doing (Sr << 18 | Sg << 9 | Sb) making at the same time their value the hash_value. If you know a good function to map that 27 bit int to an 12-13-14 bit table let me know, I currently just do the typical mod prime solution.
This is my hash_node struct:
class hash_node {
public:
unsigned int hash_value;
int repetitions;
hash_node *next;
hash_node( unsigned int hash_val,
hash_node *nxt);
~hash_node();
};
And this is the source of the problem
void hash_table::insert(unsigned int hash_value) {
unsigned int p = hash_value % tableSize;
if (table[p]!=0) { //The bucket has some elements already
hash_node *pred; //node to keep the last valid position on the list
for (hash_node *aux=table[p]; aux!=0; aux=aux->next) {
pred = aux; //last valid position
if (aux->hash_value == hash_value ) {
//It's already inserted, so we increment it repetition counter
aux->repetitions++;
} else if (hash_value < (aux->next->hash_value) ) { //The problem
//If the next one is greater than the one to insert, we
//create a node in the middle of both.
aux->next = new hash_node(hash_value,aux->next);
colisions++;
numElem++;
}
}//We have arrive to the end od the list without luck, so we insert it after
//the last valid position
ant->next = new hash_node(hash_value,0);
colisions++;
numElem++;
}else { //bucket it's empty, insert it right away.
table[p] = new hash_node(hash_value, 0);
numElem++;
}
}
This is what gdb shows:
Program received signal SIGSEGV, Segmentation fault.
0x08050b4b in hash_table::insert (this=0x806a310, hash_value=3163181) at ht.cc:132
132 } else if (hash_value < (aux->next->hash_value) ) {
Which effectively indicates I'm comparing a memory adress with a value, right?
Hope It was clear. Thanks again!
aux->next->hash_value
There's no check whether "next" is NULL.
aux->next might be NULL at that point? I can't see where you have checked whether aux->next is NULL.