C++ General Tree, Part 2

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

didijcAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ZoppoCommented:
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
Infinity08Commented:
>> 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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Infinity08Commented:
>> 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
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

itsmeandnobodyelseCommented:
>>>> 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
Infinity08Commented:
>> 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
itsmeandnobodyelseCommented:
>>>> 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
didijcAuthor Commented:
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
Infinity08Commented:
>> 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
itsmeandnobodyelseCommented:
>>>> 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
didijcAuthor Commented:
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
Infinity08Commented:
As I said, that's perfectly fine ;) Did you get it to work ?
0
didijcAuthor Commented:
I'm making a couple of adjustments as we speak... :) as soon as I'm done I'll share it with you...
0
didijcAuthor Commented:
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
didijcAuthor Commented:
Now - let's put it all together and see how everything flows...

* fingers crossed *
0
Infinity08Commented:
Let us know if you need further assistance :)
0
itsmeandnobodyelseCommented:
>>>> 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
didijcAuthor Commented:
>>>> 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
itsmeandnobodyelseCommented:
>>>> 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
Infinity08Commented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual C++.NET

From novice to tech pro — start learning today.