简体   繁体   中英

Add a node and Find Cost of Path between two given nodes in a Generic Tree with List of Children in C++

I need to make an add node function in a generic tree whose children are contained in a list. There are 2 structs that define a node in the tree (that has a label, the weight between it and its father, and a pointer to the list of its children) and a child in the list of children (that has a pointer to the child node and one to the next element in the list):

struct tree::treeNode {
    Label label;
    Weight weight;
    childrenList children;
}; //(typedef'ed as Tree)

struct tree::childrenListElem {
    treeNode* child;
    childrenListElem* next;
};

The code I've already produced works when the tree is empty (adding the root). I am incurring into a run-time error when I try to add a node to an non-empty tree.

Output tree::addElem(const Label labelOfNodeInTree, const Label labelOfNodeToAdd, const Weight w, Tree& t) {
      if ((labelOfNodeInTree == emptyLabel) && isEmpty(t)) {
        t = createNode(labelOfNodeToAdd, emptyWeight);
        return OK;
      }
    if (((labelOfNodeInTree == emptyLabel) && !isEmpty(t)) ||
       ((labelOfNodeInTree != emptyLabel) && isEmpty(t)))
        return FAILED;
    if (member(labelOfNodeToAdd, t))
        return ALREADY_PRESENT; 
    Tree v = getNode(labelOfNodeInTree, t); //here is where the problems begin to rise
    if (v==emptyTree)
        return FAILED;
    else {
        g = createNode(labelOfNodeToAdd, w);
        v->children->next->child = g;
        g = t;          
        return OK;
    }
}

Here are the createEmpty, getNode, member and isEmpty functions I've implemented:

bool tree::isEmpty(const Tree& t)
{
   return (t==emptyTree);
}

Tree getNode(const Label & l, const Tree t)
{
    Tree aux = t;
    while (!isEmpty(aux)) {
        if (aux->label == l)
            return aux;
        aux = aux->children->next->child;
    }
    return emptyTree;
}

Tree createNode(const Label l, Weight w)
{
    Tree t = new treeNode;
    t->label = l;
    t->weight = w;
    t->children = emptyChildrenList;
    return t;
}

EDIT: I've modified the member function as suggested in the function: it works only on ONE SINGLE NODE, the one given by input, and not on the entire tree: it works correctly as long as I have to search the given node in the children list of the tree (t node) given from input. I doesn't work when I try to analize the children of its children (transverse the tree on the other nodes present). Here is the member function as for now:


bool tree::member(const Label l, const Tree& t) {
    if (isEmpty(t))     return false;
    if (t->label == l)  return true;
    for (childrenList aux = t->children; aux; aux = aux->next) {
        Tree g = aux->child; 
        if (g->label == l)
                        return true;
        g->children = g->children->next;
    }
    return false;   
}

What do I do in order to make the function search for the given label in the list of children of the children of the given node?

I think the problem might be either in the getNode auxiliary function, in the member or in the last else in the addElem function, where I need to find a way so that labelOfNodeToAdd becomes one of labelOfNodeInTree's children. Did I add it correctly to the list? Does the getNode function work badly because of the aux = aux->children->next->child; line? I have a problem with imagining the list of children and therefore I am not sure how to analyze each element (to check if it is the node identified by the given label in the getNode or to check if it exists in he tree with the member).

EDIT 2: if possible, I'd like to present one last function (to find the cost (sum of weights) of a path between 2 given nodes) - since it uses the functions that have already been implemented here.

Weight tree::pathCost(const Label from, const Label to, const Tree& t)
{
    int len = 0;
    Tree da = getNode(from, t);
    Tree a = getNode(to, t);
    if (da == emptyTree || a == emptyTree)
    return notExistingPath;
    if (da == a)
        return 0;
    for (childrenList aux = t->children; aux; aux = aux->next) {
        Tree n = aux->child;
        if (aux->child == a) {
            return 0;
        }
        len += n->weight;
    }
    return len;
}

It happens to give me problems each time I try to calculate a path - is it a problem with the sums? Or does it not transverse properly?

A correct implementation of member might look like:

bool tree::member(const Label l, const Tree& t) {
    if (isEmpty(t))     return false;
    if (t->label == l)  return true;
    for (childrenList aux = t->children; aux; aux = aux->next) {
        if (member(l, aux->child))
            return true;
    }
    return false;   
}

The for loop walks the children of the node (eg one level deep), and the recursive member call is responsible for the next level down.

getNode follows the same pattern but returns a Tree :

Tree getNode(const Label & l, const Tree t)
{
    if (isEmpty(t))     return emptyTree;
    if (t->label == l)  return const_cast<Tree>(t);
    for (childrenList aux = t->children; aux; aux = aux->next) {
        Tree candidate = getNode(l, aux->child);
        if (!isEmpty(candidate))
            return candidate;
    }
    return emptyTree;
}

At that point you might as well reimplement member as:

bool tree::member(const Label l, const Tree& t) {
  return !isEmpty(getNode(l, t));
}

EDIT: The last branch of addElem is wrong too:

Output tree::addElem(const Label labelOfNodeInTree, const Label labelOfNodeToAdd, const Weight w, Tree& t) {
      if ((labelOfNodeInTree == emptyLabel) && isEmpty(t)) {
        t = createNode(labelOfNodeToAdd, emptyWeight);
        return OK;
      }
    if (((labelOfNodeInTree == emptyLabel) && !isEmpty(t)) ||
       ((labelOfNodeInTree != emptyLabel) && isEmpty(t)))
        return FAILED;
    if (member(labelOfNodeToAdd, t))
        return ALREADY_PRESENT; 
    Tree v = getNode(labelOfNodeInTree, t);
    if (v==emptyTree)
        return FAILED;
    else {
        // Get a reference to the first null pointer in the linked list
        childrenListElem*& aux = v->children;
        while (aux) {
            aux = aux->next;
        }

        // Append a new element by overwriting the pointer
        aux = new childrenListElem;
        aux->child = createNode(labelOfNodeToAdd, w);
        aux->next = nullptr;
        return OK;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM