Solved

C++ General Tree, Part 2

Posted on 2009-07-15
21
219 Views
Last Modified: 2012-05-07
Ok folks, this forum was a MAJOR help for me last time with regards to fully understanding what it is I was doing wrong and helping me get on the right path... ...I re-evaluated my code and came up with a different approach to my logic --- however, I'm running into errors...

1) error C2664: 'GenTreeNode::GenTreeNode(const GenTreeNode &)' : cannot convert parameter 1 from 'GenTreeNode *' to 'const GenTreeNode &'      -- LINE 73

2) error C2440: 'delete' : cannot convert from 'GenTreeNode' to 'void *'      -- LINE 77

3) error C2664: 'GenTreeNode::setTreeNode' : cannot convert parameter 1 from 'int *' to 'int'      -- LINE 81

4) error C2664: 'GenTreeNode::setChildren' : cannot convert parameter 2 from 'int' to 'int *'      -- LINE 82

help...
#ifndef GENERALTREE_h

#define GENERALTREE_h
 

#include <iostream>

#include <sstream>

#include <string>
 

using namespace std;
 

class GenTreeNode{

	public:

		int transactionID, totalNumChildren;

		GenTreeNode *childrenPtr;
 

		std::string toString(){

			std::ostringstream oss;

			oss<<transactionID;
 

			return oss.str();

		}
 

		void print(){

			cout<<toString()<<endl;

		}
 

		void printNode() {

			print();

			for(int i=0; i<totalNumChildren; i++){

				childrenPtr[i].printNode();

			}

		}
 

		GenTreeNode(): transactionID(0),totalNumChildren(0){

			childrenPtr = NULL;

		}
 

		GenTreeNode(int id, int cNo){

			transactionID = id;

			totalNumChildren = cNo;

			childrenPtr = new GenTreeNode[totalNumChildren];

		}
 

		void setTreeNode(int id, int cNo){

			transactionID = id;

			totalNumChildren = cNo;

			childrenPtr = new GenTreeNode[totalNumChildren];

		}
 

		~GenTreeNode(){

			if(childrenPtr != NULL){

				delete[] childrenPtr;

			}

		}
 

		void setChildren(int *tranID, int *cNos){

			for(int i=0; i<totalNumChildren; i++){

				childrenPtr[i].setTreeNode(tranID[i], cNos[i]);

			}

		}
 

		void deleeChild(GenTreeNode *ChildPtr){

			if(totalNumChildren){

				delete[] childrenPtr;

			}

		}

};
 

class GeneralTree{

	public:

		//initialize root

		GenTreeNode root;
 

		GeneralTree()   // ***** LINE 73 *****

			: root(new GenTreeNode()){}
 

		virtual ~GeneralTree(){

			delete root;   // ***** LINE 77 *****

		}
 

		void setChildren(int *tranIDs, int cNos){

			root.setTreeNode(tranIDs, cNos);   // ***** LINE 81 *****

			root.setChildren(tranID, cNos);   // ***** LINE 82 *****

		}
 

		void printTree() {

			root.printNode();

		}

};

#endif

Open in new window

0
Comment
Question by:didijc
  • 7
  • 6
  • 5
  • +1
21 Comments
 
LVL 30

Expert Comment

by:Zoppo
Comment Utility
Hi didijc,

the first two errors occur since you treat 'root' as if it was a pointer although it isn't - to solve these declare 'root' as a pointer in line 71:
> GenTreeNode* root;

To use this 'root' later replace all occurances of 'root.' with 'root->'.

The other two errors are somehow unclear to me - sure is the function 'setTreeNode' expects an 'int' but you pass a 'int*' - the 4. error IMO occurs because 'tranID' is undefined, so the compiler treats it as an 'int', but 'setChildren' expects a 'int*'

ZOPPO
0
 
LVL 53

Accepted Solution

by:
Infinity08 earned 250 total points
Comment Utility
>> to solve these declare 'root' as a pointer in line 71:

There's no real need to allocate it dynamically, is there ? So, just don't use new or delete, and you're fine. The rest of the code can then stay as it is.


>> 3) error C2664: 'GenTreeNode::setTreeNode' : cannot convert parameter 1 from 'int *' to 'int'      -- LINE 81
>>
>> 4) error C2664: 'GenTreeNode::setChildren' : cannot convert parameter 2 from 'int' to 'int *'      -- LINE 82

These are simply because you don't pass the expected type.
GenTreeNode::setTreeNode takes two ints as parameter, but you pass it an int* and an int.
GenTreeNode::setChildren takes two int*'s as parameter, but you pass it an int* and and int.
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> the 4. error IMO occurs because 'tranID' is undefined

I think it's declared elsewhere, because otherwise the compiler would have complained about it.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> There's no real need to allocate it dynamically, is there ?

If the tree could go empty we have no root. Hence, it should be a pointer which could be set to NULL.

>>>> void setChildren(int *tranIDs, int cNos){


The setChildren is obsolote with the new approach. You should/can add each child node individually.
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> If the tree could go empty we have no root. Hence, it should be a pointer which could be set to NULL.

The current code doesn't support such a thing, especially since the root node is allocated as soon as the tree is created (in the default constructor). But for a more conforming tree implementation, you're of course right ;)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> But for a more conforming tree implementation
Yes, I recently was in a thread which has *empty* nodes. It actually doesn't work very well ;-)

@didjic

It is better when the default constructor sets the root to NULL (rather than creating an empty root).

Then, you have an empty tree what you could populate by a member function like

   bool GeneralTree::isempty() { return root == NULL; }

The first insert or add function would create a new node and in case root == NULL it would assign this new node to the root (instead of adding a new child to some parent node).
0
 

Author Comment

by:didijc
Comment Utility
Why does root have to be a pointer?  Why can't I declare root as a regular variable of GenTreeNode?

If root is always the first node within my tree why not declare it right away -- in my the scenario that I am creating my root will never be empty...which is why I decided not to make it a pointer... ...
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> in my the scenario that I am creating my root will never be empty...which is why I decided not to make it a pointer... ...

And that's fine, as long as you know the limitations ;) See here : http:#24858063
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 250 total points
Comment Utility
>>>> Why does root have to be a pointer?  Why can't I declare root as a regular variable of GenTreeNode?

You can, but the pointer is the normal design.

Note, you were using pointers in the GenTreeNode to point to next sibling node and first child node. Any node in the tree has a parent node beside of the root. If you think of the tree instance as the parent of the root you have a consistent model where pointers were used to point to the next nodes and where a NULL pointer means that there is no child respectively sibling

TREE
   ->  ROOT
            |
            v
        CHILD_1        ->         CHILD_2       ->     CHILD_3
            |
            v
        GRAND_CHILD_1 ...

If you use an instance of the root in the tree as member, it means that the tree always has a root, i. e. either the tree is never empty (A) or the root can be a *empty* node which neither has a data member nor does it have any children or siblings (B)

With (B) the root member is some kind of a dummy as it neither has data nor pointers to child and sibling. That is a logical flaw with the current model as we don't have a property of GenTreeNode which tells us that it is empty. We would need to add a bool member 'isempty' to being able to handle it. Or we must have some data value which tells us that the root node was empty. Or we need to add an item  counter in the tree so that we *know* that the root is empty (since the counter is 0). Or we have a root node which generally doesn't count but is only the anchor node. All these ways out are bad design (maybe beside of the anchor node). It is not good if we add members which handle only one special node. And it is not good to have special data values what would be a limitation for the tree without need.

That's why the normal solution is to have a pointer member for root in the tree. If this pointer is NULL the tree is empty. If not it has at least one element which is the element stored with the root node.

0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:didijc
Comment Utility
itsmeandnobodyelse / Infinity08 -- I completely understand what the each of you are saying...however, in my grand scheme, the ROOT/ tree will never be empty...

8 << * this will never be an "empty" / NULL value *
|
8,1------------------ 8,2 ----------------- 8,3 ----------------- ... ----------------- 8,n
                                |
                                |
                                8,2,1 ----------------- 8,2,2 ----------------- 8,2,3 ... ----------------- 8,2,n
                                                                                                     |
                                                                                                     |
                                                                                                     8,2,3,4 ----------------- 8,2,3,4
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
As I said, that's perfectly fine ;) Did you get it to work ?
0
 

Author Comment

by:didijc
Comment Utility
I'm making a couple of adjustments as we speak... :) as soon as I'm done I'll share it with you...
0
 

Author Comment

by:didijc
Comment Utility
Ok so here's my fix * based on talking with itsmeandnobodyelse & Infinity08 * -- damn you guys are good, I only hope to be as good eventually...
#ifndef GENERALTREE_h

#define GENERALTREE_h
 

#include <iostream>

#include <sstream>

#include <string>
 

using namespace std;
 

class GenTreeNode{

	public:

		int transactionID, totalNumChildren;

		GenTreeNode *childrenPtr;
 

		std::string toString(){

			std::ostringstream oss;

			oss<<transactionID;
 

			return oss.str();

		}
 

		void print(){

			cout<<toString()<<endl;

		}
 

		void printNode() {

			print();

			for(int i=0; i<totalNumChildren; i++){

				childrenPtr[i].printNode();

			}

		}
 

		GenTreeNode(): transactionID(0),totalNumChildren(0){

			childrenPtr = NULL;

		}
 

		GenTreeNode(int id, int cNo){

			transactionID = id;

			totalNumChildren = cNo;

			childrenPtr = new GenTreeNode[totalNumChildren];

		}
 

		void setTreeNode(int id, int cNo){

			transactionID = id;

			totalNumChildren = cNo;

			childrenPtr = new GenTreeNode[totalNumChildren];

		}
 

		~GenTreeNode(){

			if(childrenPtr != NULL){

				delete[] childrenPtr;

			}

		}
 

		void setChildren(int *tranID, int *cNos){

			for(int i=0; i<totalNumChildren; i++){

				childrenPtr[i].setTreeNode(tranID[i], cNos[i]);

			}

		}
 

		void deleeChild(GenTreeNode *ChildPtr){

			if(totalNumChildren){

				delete[] childrenPtr;

			}

		}

};
 

class GeneralTree{

	public:

		//initialize root

		GenTreeNode root;
 

		GeneralTree(){}
 

		virtual ~GeneralTree(){}
 

		void setChildren(int *tranIDs, int *cNos){

			root.setTreeNode(*tranIDs, *cNos);

			root.setChildren(tranIDs, cNos);

		}
 

		void printTree() {

			root.printNode();

		}

};

#endif

Open in new window

0
 

Author Comment

by:didijc
Comment Utility
Now - let's put it all together and see how everything flows...

* fingers crossed *
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
Let us know if you need further assistance :)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> void deleeChild(GenTreeNode *ChildPtr){
It probably should mean deleteChild and as it deletes all children you better name it deleteChildren.

Moreover the childrenPointer must be set to NULL after delete and the totalNumChildren to 0, or the next traversal will crash.
0
 

Author Comment

by:didijc
Comment Utility
>>>> Moreover the childrenPointer must be set to NULL after delete and the totalNumChildren to 0, or the next traversal will crash

Doesn't the constructor take care of that...

[code]
GenTreeNode(): transactionID(0),totalNumChildren(0){
     childrenPtr = NULL;
}
[/code]
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> Doesn't the constructor take care of that...
The constructor is a first-time (one time) initialitation. It couldn't help when child nodes were deleted.
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
Based on the author's post http:#24864333, I'd say the question has been resolved.

I suggest a PAQ for http:#24858063 (Infinity08) and http:#24864032 (itsmeandnobodyelse), based on the names mentioned by the author in his post.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now