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);
}
}
Related
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.
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 wrote the following function, as an implementation of this algorithm/approach, to generate the power-set (set of all subsets) of a given string:
vector<string> getAllSubsets(string a, vector<string> allSubsets)
{
if(a.length() == 1)
{
// Base case,
allSubsets.push_back("");
allSubsets.push_back(a);
}
else {
vector<string> temp = getAllSubsets(a.substr(0,a.length()-1),allSubsets);
vector<string> with_n = temp;
vector<string> without_n = temp;
for(int i = 0;i < temp.size()-1;i++)
{
allSubsets.push_back(with_n[i] + a[a.length()-1]);
allSubsets.push_back(without_n[i]);
}
}
return allSubsets;
}
however, someone appears to be going wrong: the size of temp and allSubsets remains static from recursive call to recursive call, when they should be increasing due to the push_back() calls. is there any reason why this would take place?
It's because you have an off-by-one error. Because this occurs in your next-to-base case, you are never inserting any entries.
Since the first invalid index is temp.size(), i < temp.size() means that you will always have a valid index. Subtracting 1 means that you are missing the last element of the vector.
It's worth noting that passing allSubsets in as a parameter is kinda silly because it's always empty. This kind of algorithm simply doesn't require a second parameter. And secondly, you could be more efficient using hash sets that can perform deduplication for you simply and quickly.
Having used the various search engines (and the wonderful stackoverflow database), I have found some similar situations, but they are either far more complex, or not nearly as complex as what I'm trying to accomplish.
C++ List Looping
Link Error Using Templates
C++:Linked List Ordering
Pointer Address Does Not Change In A Link List
I'm trying to work with Link List and Node templates to store and print non-standard class objects (in this case, a collection of categorized contacts). Particularly, I want to print multiple objects that have the same category, out of a bunch of objects with different categories. When printing by category, I compare an sub-object tmpCategory (= "business") with the category part of a categorized contact.
But how to extract this data for comparison in int main()?
Here's what I'm thinking. I create a GetItem member function in LinkList.tem This would initialize the pointer cursor and then run a For loop until the function input matches the iteration number. At which point, GetItem returns object Type using (cursor -> data).
template <class Type>
Type LinkList<Type>::GetItem(int itemNumber) const
{
Node<Type>* cursor = NULL;
for(cursor = first;
cursor != NULL;
cursor = (cursor -> next))
{
for(int i = 0; i < used; i++)
{
if(itemNumber == i)
{
return(cursor -> data);
}
}
}
}
Here's where int main() comes in. I set my comparison object tmpCategory to a certain value (in this case, "Business"). Then, I run a For loop that iterates for cycles equal to the number of Nodes I have (as determined by a function GetUsed()). Inside that loop, I call GetItem, using the current iteration number. Theoretically, this would let the int main loop return the corresponding Node from LinkList.tem. From there, I call the category from the object inside that Node's data (which currently works), which would be compared with tmpCategory. If there's a match, the loop will print out the entire Node's data object.
tmpCategory = "Business";
for(int i = 0; i < myCategorizedContact.GetUsed(); i++)
{
if(myCategorizedContact.GetItem(i).getCategory() == tmpCategory)
cout << myCategorizedContact.GetItem(i);
}
The problem is that the currently setup (while it does run), it returns nothing at all. Upon further testing ( cout << myCategorizedContact.GetItem(i).getCategory() ), I found that it's just printing out the category of the first Node over and over again. I want the overall scheme to evaluate for every Node and print out matching data, not just spit out the same Node.
Any ideas/suggestions are greatly appreciated.
Please look at this very carefully:
template <class Type>
Type LinkList<Type>::GetItem(int itemNumber) const
{
Node<Type>* cursor = NULL;
// loop over all items in the linked list
for(cursor = first;
cursor != NULL;
cursor = (cursor -> next))
{
// for each item in the linked list, run a for-loop
// counter from 0 to (used-1).
for(int i = 0; i < used; i++)
{
// if the passed in itemNumber matches 'i' anytime
// before we reach the end of the for-loop, return
// whatever the current cursor is.
if(itemNumber == i)
{
return(cursor -> data);
}
}
}
}
You're not walking the cursor down the list itemNumber times. The very first item cursor references will kick off the inner-for-loop. The moment that loop index reaches itemNumber you return. You never advance your cursor if the linked list has at least itemNumber items in the list.. In fact, the two of them (cursor and itemNumber) are entirely unrelated in your implementation of this function. And to really add irony, since used and cursor are entirely unrelated, if used is ever less than itemNumber, it will ALWAYS be so, since used doesn't change when cursor advances through the outer loop. Thus cursor eventually becomes NULL and the results of this function are undefined (no return value). In summary, as written you will always either return the first item (if itemNumber < used), or undefined behavior since you have no return value.
I believe you need something like the following instead:
template< class Type >
Type LinkList<Type>::GetItem(int itemNumber) const
{
const Node<Type>* cursor = first;
while (cursor && itemNumber-- > 0)
cursor = cursor->next;
if (cursor)
return cursor->data;
// note: this is here because you're definition is to return
// an item COPY. This case would be better off returning a
// `const Type*` instead, which would at least allow you to
// communicate to the caller that there was no item at the
// proposed index (because the list is undersized) and return
// NULL, which the caller could check.
return Type();
}
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.