Ok I have been working on a class to iterate through all nodes in an html doc and return the data that I need. This is very simple and I have achieved this in Bash but now I am trying to port the same to C++.
I started with the example on the libxml site but I have stepped through this function node by node and I can't understand how it is working.
Here is the function:
static void
print_element_names(xmlNode * a_node)
{
xmlNode *cur_node = NULL;
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
printf("node type: Element, name: %s\n", cur_node->name);
}
print_element_names(cur_node->children);
}
}
So basically, this function takes a node assigns it to a pointer, and starts to loop through all sibling nodes, but if the current node has children, it calls the function and start over on that child node. This is all very understandable.
So it drives down the doc structure, but how does it navigate back up the structure?
Does xmlNode->children return the next parent node when it is found NULL? As far as I can tell, this is not true, but I just can't figure out how this is working.
I successfully created a class to do what I want, but it is so much more complex than this and about 10 lines longer. I actually had to check if the next node was null and either navigate down if it has children or navigate back up and to the next node if it didn't.
This example is much simpler and I would like to understand how to make my code better.
So it drives down the doc structure, but how does it navigate back up the structure?
What you have posted is a recursive function. From the nature of your question, I'm assuming you don't quite understand what recursion is/how it works. A quick google search should give you some good information/examples.
Does xmlNode->children return the next parent node when it is found NULL?
I am assuming that xmlNode->children returns a pointer to a linked list containing all children of the current node. If the current node has no children, it would probably return NULL.
This example is much simpler and I would like to understand how to make my code better.
I am assuming the class you wrote was purely iterative. Recursive functions can greatly simplify code, but performance wise they can cause issues on larger data sets. I would definitely recommend reading up on them; they can be quite fun.
Solving the problem iteratively is essentially a tree traversal. You will need a stack to accomplish this. The stack can probably be most easily implemented as a singly-linked-list.
// interface to be implemented
typedef void* Stack;
Stack stack_new(); // creates a new stack
void stack_add(Stack stack, xmlNode *element); // adds an element to the stack
int stack_size(); // returns the number of elements currently in the stack
xmlNode* stack_remove(Stack stack); // pops an element from the stack
void stack_free(Stack stack); // frees up resources used by the stack
// printing code
static void print_element_names(xmlNode *a_node)
{
Stack stack = stack_new();
stack_add(stack, a_node);
while(stack_size(stack))
{
xmlNode *cur_node = stack_remove(stack);
if(cur_node->children) stack_add(cur_node->children);
xmlNode *iter_node = NULL;
for (iter_node = cur_node; iter_node; iter_node = iter_node->next)
{
if (iter_node->type == XML_ELEMENT_NODE)
printf("node type: Element, name: %s\n", iter_node->name);
}
}
stack_free(stack);
}
Related
I managed to figure out the answer to this question as I was writing it. Keeping it posted to hopefully aide future devs that run into similar issue.
Here's a quick rundown:
I have a directed, weighted map class.
I keep track of all my nodes in: vector<Node> nodes;
I keep track of all the nodes' adjacent nodes in map<Node, <map<Node, int>> connections
When I try doing a traversal through the Graph and I reach a node that does not have any adjacent nodes it will crash the program because my map throws out_of_range exception.
After looking online I see someone has the solution of using this line of code when they are adding nodes: (void) connections[node];. If I remove this line of code, I get the out_of_range exception from the map class's .at() function, but with this line of code, it somehow avoids that exception.
My Question: What is the line of code doing that avoids the exception from being thrown?
My best guess right now is that the line of code is somehow creating an empty adjacency list and my for-each loop doesn't get the exception
set<Node> nodes; // {n1, n2...nn}
map<Node, map<Node, int>> connections; //Connections between the nodes and their weights
//Add node to graph
void add(Node node) {
nodes.insert(node); //add to node list
(void) connections[node]; //This is the magic line!!
}
bool DFS(N start, N target) {
for (Node node : nodes) {
//This for-each loop crashes when the node in the .at() doesn't exist in the connections map
for (pair<N, int> connectedNode : connections.at(node)) {
if (target == connectedNode.first) {
return true;
}
}
}
return false;
}
As I was writing the question I was able to answer my own question. Love a good Rubber Ducky moment. Hopefully, this question can aide future devs who also miss the very basic answer to this question.
In stl::map the [ ] operator will get a reference to the value of the key inside the [ ] if it exists, if it doesn't exist it creates one.
So in the add(Node node) function the (void)connections[node] was actually creating the node in the adjacency map.
The (void) before the line is telling the compiler to ignore any warnings about this because it's technically an incomplete line of code (according to the compiler). Read more about the meaning of (void) here
i asked my professor to give me an old homework from another semester. And its about building a family tree and then finding the kinship between two nodes given. The family tree is about namekians (Dragon ball z) so every namekian has a single father.
The thing is that the input its something like this:
First name is the parent Second name is the child
Iolin Lyre
Iolin Piyano
Batu Iolin
Batu Okiat
Ollusc Xylo
Organa Murd
Piccoro Ollusc
Piccoro Rombone
Rombone Organa
So i must have two trees, one with Piccoro as the leader (he is always the leader of one tree) and another with unknown leader.
The thing is that i have trouble when i try to create the trees, i know i have two roots, but as you can see the input is not in order so ill have nodes without parent until i read and create its parent. For example, i create Ollusc and its child Xylo, and then Organa and Murd, but i only have one root to represent that tree (Also i dont know if they are in the same tree or not) so i dont know how to "save" those nodes to connect them later, same happens with Organa and Rombone, Organa will be somewhere until i create Rombone and then connect him with Organa.
Batu------>NULL
/ \
Iolin--->Okiat->NULL
/ \
Lyre-->Piyano->NULL
Piccoro-----> NULL
/ \
Ollusc--->Rombone->NULL
/ /
Xylo->NULL Organa->NULL
/
Murd->NULL
I thought about saving nodes into a Queue or maybe a Stack because i dont know how much nodes will be floating somewhere until i connect them, but save them into a queue and then what?, because when i think about my next step i don't know what to do.
Maybe store a node into the queue until a node Parent appears, and then take that node from queue, but queue its FIFO and doesnt help too much i think, because what if i need to take the second node or maybe the third instead of the front one.
So maybe store them into a aux list?
I should add a node to a list,Queue,stack if they have no parent and they are not the root right? or should i add the root to the list,Queue,Stack?
Because i'm using root to build the tree
In the first Tree my root its Iolin until batu appears and i change it to batu
In the second tree Root will be always Piccoro, but its a little difficult to build a tree starting with piccoro because i dont know his childs
What do you think? what should i do? Do you have better or other ideas?
int main(int argc, char const *argv[])
{
FILE *fpInput,*fpOutput;
fpInput = fopen("input.in","r");
fpOutput = fopen("output.out","w");
if ((fpInput == NULL)){ printf("Open File Error\n"); exit(1); }
// To read a line of the file
char *fpInputString;
char *parentInput, *childInput;
// Because i dont know the number of lines that comes next, read until a number is found
// That number is the number of consult of kinship about namekians
fpInputString = inputString(fpInput,5);
while ((strlen(fpInputString) != 1) && (strlen(fpInputString) != 2) && (strlen(fpInputString) != 3))
{
parentInput = strtok(fpInputString," ");
childInput = strtok(NULL,"\0");
fpInputString = inputString(fpInput,5);
}
fclose(fpInput);
fclose(fpOutput);
return 0;
}
InputString Function reads a whole line from a file
tree.h
// Struct of a node
struct treeNode
{
// Name
char *name;
// Pointers
struct treeNode *parent;
struct treeNode *firstChild;
struct treeNode *nextSibling;
struct treeNode *prevSibling;
};
I'll be very thankful if you help me, i know it can be hard to understand me or my code
But i really want to learn new things about coding, i don't know if this homework will be better if i do it in c++ because c doesn't have STL
Save input information with map.
Find the ancestor node.
Add child nodes to the ancestor node.
Don't build trees for a node if it is not a ancestral node.
I am trying to implement recursive method to set recursively the height at each node. Partially solution is achieved, however I am not entirely sure where I could decrement height and check if particular node in-Order traversal is complete. My program is based on this implementation: http://visualgo.net/bst.html
Thank you
If you mean for height here to represent the level of the tree that a node is on, using a global variable is going to give you pretty weird results. I also admit to not being entirely sure what you are doing with the variable u.
That said, I think you should be okay with something like this:
public void setHeight(struct node *r, int h = -1) {
// pointer pointing to null, return
if(r == NULL) {
return;
}
h++; // increment height
r.height = h; // set update height to a current node
setHeight(r ->u.lc, h); // traverse the list pointing to the left child
visit(r) // visit pointing node
setHeight(r ->u.rc, h); // visit right child of the node
}
Edit: I don't have the reputation to comment yet, so I'm limited to responding with edits. #ProgLearner, you don't need a separate variable u because your node pointer is a function argument, and so you'll have a fresh one with every call to the function. Similarly, as Jonathan Mee said, the h variable needs no external initialization because it's also local to the function. In cases where you don't supply any initial value (like when you call it on the root), it will default to -1.
I'm working on an AVL Tree Project (almost finished after lots of hours of programming) and I wonder if it's possible to keep data from the calling recursion. This is the code:
node* previous;
//Visits the nodes by level recursively (post-order traversal), so that it can calculate the balance of each node (updates heights when deleting a node with two children)
void AVLTree::updateTreeHeights(node *ptr)
{
if(ptr==root)
previous=root;
if(ptr==NULL)
return;
updateTreeHeights(ptr->leftChild);
updateTreeHeights(ptr->rightChild);
if(ptr->leftChild==NULL && ptr->rightChild==NULL)
{
ptr->heightL=ptr->heightR=0;
}
else if(ptr->leftChild==NULL)
{
ptr->heightR=max(ptr->rightChild->heightL,ptr->rightChild->heightR)+1;
ptr->heightL=0;
}
else if(ptr->rightChild==NULL)
{
ptr->heightL=max(ptr->leftChild->heightL,ptr->leftChild->heightR)+1;
ptr->heightR=0;
}
else
{
ptr->heightL=max(ptr->leftChild->heightL,ptr->leftChild->heightR)+1;
ptr->heightR=max(ptr->rightChild->heightL,ptr->rightChild->heightR)+1;
}
ptr->balance=ptr->heightR-ptr->heightL;
if(ptr->balance>1)
balanceTree(ptr,previous,ptr->rightChild);
else if(ptr->balance<-1)
balanceTree(ptr,previous,ptr->leftChild);
}
Here's what I want! I want to keep the ptr value from the calling recursion and save it to the gloabal variable named previous (it's not necessery to be global, but I figured that it must be the only way). For example if ptr points at number 20 and then we call the recursive function for ptr's leftChild (e.g. updateTreeHeights(ptr->leftChild);) I want to keep number 20 (previous=ptr;). Is it possible somehow? I'm not really good with recursion! (Don't tell! :P )
I don't see why not. You can make a global variable and then just copy it over from updateTreeHeights. Just keep a look out for making sure the copy happens only once, and also by doing previous=ptr previous will be pointing to the entire node. So you might have to dive a little deeper in the node to get the date you want.
I'm sorry if the title isn't very explicit, but I'll try to explain it better. I'm not very familiar with c++ and I'm using openFrameworks for the first time. I'm trying to do something that's probably quite easy, at least in other languages it is, but I'm not being able to do it :(
I have a class Video and inside it I have an object list<ofImage> keyFrames; and several methods to interact with it like the following:
void addKeyFrame(ofImage img) {
if(keyFrames.size() == 0) {
keyFrames.push_front(img);
}
else {
keyFrames.push_back(img);
}
}
list<ofImage> * getKeyFrames() {
list<ofImage> *list = &keyFrames;
return list;
}
void clearKeyFrames() {
keyFrames.clear();
}
In other class I have several Video objects and I have a function that uses addKeyFrame(ofImage img) to fill the list for each object. In the end of that function if I print the list size it is greater than zero.
Inside draw() function I iterate each Video object and I try to draw each image inside their keyFrame list, but the list is always empty and I just filled it with images... I'm using getKeyFrames() function to return a pointer to the list. How can it be empty if I just added objects to it in another function and if I verified that the size was greater than zero? And if I try to debug the application I feel even more lost lol.
Please tell me if you need anymore information and if you know what I'm doing wrong. Thanks!
Ok, A few little things:
1- You shouldn't check for empty lists (or any other STL containers) like this:
if(keyFrames.size() == 0)
This is faster and more "stylish":
if(keyFrames.empty())
2- You've created an unnecessary variable here:
list<ofImage> * getKeyFrames() {
list<ofImage> *list = &keyFrames;
return list;
}
You could do just:
list<ofImage> * getKeyFrames() {
return &keyFrames;
}
3- Pointers are not (most times) the best solution in C++. A reference is the most used substitute, but it would be even better in htis case if you returned an iterator:
list<ofImage>::iterator GetBeginIterator() {
return keyFrames.begin();
}
This way you could use the iterator just like a pointer, increasing it to iterate trough the frames and dereferencing it (with * operator)...