Recursively Populate N-ary Tree in c++ - c++

I'm attempting to create the game tree of the tic-tac-toe board game. I've written some basic methods, but I'm having trouble recursively populating the elements of the tree.
I'm using a Node struct to define the Nodes of the tree. Each node has an array of children.
struct node {
string data;
int height;
node * child[9];
};
Each Node stores the content of a game board as a string. * is used to display blanks.
So, * * * * * * * * * would be a blank board.
I have a Tree class that implements the tree.
class Tree {
public:
Tree();
Tree(string data);
~Tree();
void insert(string data, node * leaf);
node * get_root();
void populate(node * n);
void generate_tree(node * n);
int number_of_blanks(string);
private:
void destroy_tree(node * leaf);
node * root;
node * temp;
int count;
};
Tree::Tree(string data) {
root = new node;
root->data = data;
root->height = 0;
temp = root;
count = 0;
}
Here is my method for inserting nodes. It inserts a new node to the first NULL child.
void Tree::insert(string data, node * leaf) {
int i;
//checks for first NULL child
for(i = 0; i < 9; i++) {
if(leaf->child[i] == NULL) {
//first NULL child is inserted and all its children set to NULL
leaf->child[i] = new node;
leaf->child[i]->data = data;
leaf->child[i]->height = leaf->height + 1;
break;
}
}
}
This code works how I've intended it to, however I'm sure it's not the best method.
Where I'm having the most trouble is recursively populating the tree. My recursion either ends early, or is an endless loop. I'm not sure how to approach this problem, as I've never used recursion with a void method.
void Tree::generate_tree(node * leaf) {
int i;
string data;
string player;
int length = number_of_blanks(leaf->data);
if(leaf->height % 2 == 0)
player = "X";
else
player = "O";
if(leaf->data.find_last_of('*',8) == string::npos) {
cout << "This is a leaf!!!!!!!!! " << leaf->data << endl;
return;
}
for(i = 0; i < length; i++) {
if(leaf->height >=9 )
return;
data = leaf->data.replace(count,1,player);
insert(data,leaf);
cout << "New Node: " << data << " Height: " << leaf->child[i]->height << endl;
count++;
generate_tree(leaf->child[i]);
count = 0;
}
}
Any tips, or specific suggestions would be greatly appreciated. Thank you.

I'd recommend giving node a constructor and to initialize members before the code block that makes up the constructor. For example:
node(string s, int h) : data(s), height(h) {
for (int i=0;i < 9; ++i)
child[i] = NULL;
}
Similarly for the constructor for Tree:
Tree::Tree(std::string data) : root(new node(data,0)), count(0) {}
This makes other parts of the code much simpler. For example, your insert code would now look like this:
void Tree::insert(std::string data, node * leaf) {
//checks for first NULL child
for(int i = 0; i < 9; i++) {
if(leaf->child[i] == NULL) {
//first NULL child is inserted and all its children set to NULL
leaf->child[i] = new node(data, leaf->height+1);
break;
}
}
}
I haven't had the time to analyze the rest, but this may make it easier for you to solve.

Related

basic insertion sort in linked list with logic problem (maybe it is because pointer)

I write a code for insertion sort for integer data in linked list in c++, I referred to the algorithms on the Internet, and finally took the following code using array as a basic concept for my version.
however, the sorting always ignore my first element,(but all the other element is ordered well).
I have tried checking my loop statement, checking the pointer address while looping (because my key pointer loop at first time didn't go into the judge pointer loop), checking the shifting mechanism while comparing, but I cannot find my logic problem.
(I know someone would said I doesn't provide enough data for you to help me, but I have been checking these things for two days, including asking friends and searching the solutions existed on website. So I really hope someone can answer me without blame, thank you.)
array version(on the internet)
#include <iostream>
void InsertionSort(int *arr, int size){
for (int i = 1; i < size; i++) {
int key = arr[i];
int j = i - 1;
while (key < arr[j] && j >= 0) {
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
}
linked list version(by my own)
Node class used in my version
class Node
{
public:
Node()
{
next = NULL;
pre = NULL;
}
Node(int n)
{
data = n;
next = NULL;
pre = NULL;
}
int getData() { return data; }
Node *getNext() { return next; }
Node *getPre() { return pre; }
void setData(int d) { data = d; }
void setNext(Node *n) { next = n; }
void setPre(Node *p) { pre = p; }
private:
int data;
Node *next, *pre;
};
class List
{
public:
List() { list = NULL; }
List(int n) { generate(n); }
void generate(int n)
{
int j;
list = NULL;
for(j = 0;j < n;j ++)
generate();
}
void generate()
{
Node *buf = new Node(rand());
buf->setNext(list); //list->NODE2.next->NODE1.next->NULL
if(list != NULL)
list->setPre(buf);
list = buf;
}
void insertionSort()
{
bool breakByCompare;
Node* keyptr;
Node* judgeptr;// judge is the value that is going to compare with key
int key;
for(keyptr = list->getNext(); keyptr != NULL;
keyptr = keyptr->getNext()){
//if we set list as 5,7,6 ; 6 is key
key = keyptr->getData();//store the key value for the setting after shifting
breakByCompare = 0;
for(judgeptr = keyptr->getPre() ; judgeptr->getPre()!= NULL;
judgeptr= judgeptr->getPre()){
//list: 5,7,6 ; 7 is judge
if(judgeptr->getData() > key){
// 7>6, so we shift 7 to the position which was for 6
judgeptr->getNext()->setData(judgeptr->getData());// list: 5,7,7 ;
cout << judgeptr->getData() << " , " << keyptr->getData() << endl;
}
else{
break;
}
}
judgeptr->getNext()->setData(key);// list: 5,6,7
}
}
void print()
{
Node *cur = list;
while(cur != NULL)
{
cout<<cur->getData()<<" ";
cur = cur->getNext();
}
cout<<endl;
}
private:
Node *list;
};
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define SIZE 100
int main()
{
srand(time(NULL));
List *l = new List(10);
l->print();
l->insertionSort();
l->print();
}
One of the most important difference between a linked list and an array is that it is sometimes required to handle the first element as a special case.
Here is a fixed version of your sorting method :
void insertionSort()
{
bool breakByCompare;
Node* keyptr;
Node* judgeptr;
int key;
for(keyptr = list->getNext(); keyptr != NULL; keyptr = keyptr->getNext()){
key = keyptr->getData();
breakByCompare = 0;
// I replaced judgeptr->getPre() by judgeptr in the condition
// to allow the backward loop to go until the root
for(judgeptr = keyptr->getPre() ; judgeptr != NULL; judgeptr= judgeptr->getPre()){
if(judgeptr->getData() > key){
judgeptr->getNext()->setData(judgeptr->getData());
cout << judgeptr->getData() << " , " << key << endl;
}
else break;
}
// Here is the special case : we must support a null judgeptr
// and replace its next element by the list
if (judgeptr) judgeptr->getNext()->setData(key);
else list->setData(key);
}
}

Implementing a recursive Void function (Finding height of Binary Search Tree)

I need to implement a void function that computes the height of each node in a binary tree and stores it in each node. I've found a few solutions online that are recursive in nature but they return int. Examples include (https://www.geeksforgeeks.org/write-a-c-program-to-find-the-maximum-depth-or-height-of-a-tree/). The difference between the model answer, besides that it is not a void function, is that it also does not store the height in each node.
This is my attempt at the solution, but I can't seem to get the code to work, nor refit the model answer to recursively apply in a void function. When I run my code in the helper code to test, it doesn't even show any output.
void computeHeight(Node *n) {
Node* ltraverser = n;
Node* rtraverser = n;
int lheight = 0;
int rheight =0;
if (n == NULL) {
n->height = 0;
}
while (ltraverser->left != NULL) {
ltraverser = ltraverser->left;
lheight += 1;
}
while (rtraverser->right != NULL) {
rtraverser = rtraverser->right;
lheight += 1;
}
if (lheight > rheight) {
n->height = lheight;
}
else {
n->height = rheight;
}
computeHeight(n->left);
computeHeight(n->right);
}
For reference:
The starter code below defines a class called "Node" that has two child pointers ("left" , "right") and an integer "height" member variable. There is also a constructor Node() that initializes the children to nullptr and the height to -1.
/*
The height of a node is the number of edges in
its longest chain of descendants.
Implement computeHeight to compute the height
of the subtree rooted at the node n. Note that
this function does not return a value. You should
store the calculated height in that node's own
height member variable. Your function should also
do the same for EVERY node in the subtree rooted
at the current node. (This naturally lends itself
to a recursive solution!)
Assume that the following includes have already been
provided. You should not need any other includes
than these.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
You have also the following class Node already defined.
You cannot change this class definition, so it is
shown here in a comment for your reference only:
class Node {
public:
int height; // to be set by computeHeight()
Node *left, *right;
Node() { height = -1; left = right = nullptr; }
~Node() {
delete left;
left = nullptr;
delete right;
right = nullptr;
}
};
*/
For testing the code
// This function prints the tree in a nested linear format.
void printTree(const Node *n) {
if (!n) return;
std::cout << n->height << "(";
printTree(n->left);
std::cout << ")(";
printTree(n->right);
std::cout << ")";
}
Node *n = new Node();
n->left = new Node();
n->right = new Node();
n->right->left = new Node();
n->right->right = new Node();
n->right->right->right = new Node();
computeHeight(n);
printTree(n);
std::cout << std::endl << std::endl;
printTreeVertical(n);
delete n;
n = nullptr;
return 0;
}
Instead of returning node height just recurisvely call computeHeight on left and right nodes, then store maximum height in node structure.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
class Node {
public:
int height;
Node *left, *right;
Node() { height = -1; left = right = nullptr; }
~Node() {
delete left;
left = nullptr;
delete right;
right = nullptr;
}
};
void computeHeight(Node *node) {
if (node == nullptr) {
return;
}
computeHeight(node->left);
computeHeight(node->right);
int leftHeight = -1;
int rightHeight = -1;
if (node->left != nullptr) {
leftHeight = node->left->height;
}
if (node->right != nullptr) {
rightHeight = node->right->height;
}
node->height = std::max(leftHeight, rightHeight) + 1;
}
void printNode(Node *n, int level = 0) {
if (n == nullptr) {
return;
}
std::cout << std::string(level * 2, ' ') << "Height = " << n->height << "\n";
printNode(n->left, level + 1);
printNode(n->right, level + 1);
}
int main() {
Node *n = new Node();
n->left = new Node();
n->right = new Node();
n->right->left = new Node();
n->right->right = new Node();
n->right->right->right = new Node();
computeHeight(n);
printNode(n);
}
Your mistake is on the following part and because of this you program exits without showing the error
if (n == NULL) {
n->height = 0;
}
When n is NULL; you should not try to access n->height. Replace it as follows and your code will work:
if (n == NULL) {
return;
}
Also, as the other answer mentioned, when you want to compute height recursively, you don't need a while loop just use the following recursive formula:
Height(n) = 1 + max(Height(n->left), Height(n->right))
Also, for consistency reasons usually the height of NULL subtree is defined to be -1. This allows the recursive formula to work properly.
Word of advice: In order to debug any program, an easy way is to just print messages before and after function calls and/or certain lines. This way by checking which messages are not printed, you can quickly pinpoint which functions/lines are causing a problem and then investigate them.

Program hangs up after loop counter input - no infinite loop or seg fault

I'm having an issue I can't figure out how to diagnose. It's been a while since I've worked in C++ and I decided to write a class based implementation of a LLL, with one class for the node and one for the list for the sake of practice. Once the list has been initialized in main, it prompts the user to input the length of the list from within the constructor. Then, for some reason, it hangs up instead of generating the list. I haven't gotten any error codes, and it doesn't seem to be stuck in a loop as best as I can tell. I'm very confused.
Main function:
int main() {
LLL * myList = new LLL();
int displayCount = 0;
displayCount = myList->display();
cout << "\n\n" << displayCount << " nodes were displayed\n\n";
delete myList;
return 0;
}
LLL constructor:
LLL::LLL() {
head = new node(rand() % 20);
node * current = head;
cout << "\n\nHow many nodes would you like this list to be? ";
int length = 0;
cin >> length;
cin.ignore(1000);
for (int i = 1; i <= length; ++i) {
node * temp = new node(rand() % 20);
current->attachNext(temp);
current = temp;
delete temp;
}
Node constructor:
node::node(int data) {
this->next = NULL;
this->data = data;
}
attachNext function:
bool node::attachNext(node *& toAttach) {
this->next = toAttach;
return true;
}
Header file:
#include <iostream>
#include <math.h>
using namespace std;
class node {
public:
node();
node(int data);
~node();
node * traverse();//returns obj->next node
bool checkNext();//returns true if obj->next exists
bool attachNext(node *& toAttach);
int display();
int deleteAll(int & count);
private:
node * next;
int data;
};
class LLL {
public:
LLL();
LLL(int length);
~LLL();
int display();
private:
node * head;
};
Ok, I figured it out. I called the cin.ignore function in the LLL and forgot to specify the delimiter.
This:
cin.ignore(1000);
Should have been:
cin.ignore(1000, '\n');

Insert into n-ary tree using Queue

I have a simple n-ary (3 child nodes maximum) whereby the first node inserted will be the root. Before, I add any other node, I have to search the tree and insert as a child node from a previously inserted node, if a condition is meet.
My insertion methods is overloaded for first insertion and subsequent insertions.
I was able to insert the first node using this method:
void Tree::AddSkill(char* name, char* desc, int level)
{
Skill s(name, desc, level);
Node * newNode = new Node(s);
//newNode->aSkill = Skill(name, desc, level);
newNode->parent = NULL;
for (int i = 0; i<CHILD_MAX; i++)
{
newNode->children[i] = NULL;
}
if (this->root == NULL)
{
this->root = newNode;
}
else
{
this->root->parent = newNode;
newNode->children[0] = this->root;
this->root = newNode;
}
}
I'm having a few issues with subsequent insertion into the tree,
Here is the code I have so far:
void Tree::AddSkill(char* name, char* desc, int level, char* parentName)
{
if (this->root == NULL)
{
cout << "Error: no nodes in tree.\n";
return;
}
Node* node = NULL;
Skill s(name, desc, level);
Node * child = new Node(s);
while (root != NULL)
{
if (strcmp(child->aSkill.GetName(), parentName) == 0)
{
for (int i = 0; i < CHILD_MAX; i++)
{
if (node->children[i] == NULL)
{
child->aSkill = s;
child->parent = node;
node->children[i] = child;
return;
}
}
}
}
}
When I run the code through VS Debugger, the while loop in the second AddSkill method repeats endlessly.
I'm not so sure what I'm doing wrong or what concept I need to implement, any help will be appreciated.
P.S. This is an Homework (Not sure what the appropriate tag is).
Update:
I have tried to implement the overloaded AddSkill() using Queue.
This is what I've tried with it.
void SkillTree::AddSkill(char* name, char* desc, int level, char* parentName)
{
if (this->root == NULL)
{
cout << "Error: no nodes in tree.\n";
return;
}
queue<Node*> q;
q.push(this->root);
while (!q.empty())
{
Node * n = q.front();
q.pop();
if (strcmp(n->aSkill.GetName(), parentName) == 0)
{
for (int i = 0; i<CHILD_MAX; i++)
{
if (n->children[i] == NULL)
{
Skill s(name, desc, level);
Node * child = new Node(s);
//When I comment out the next 3 lines, program does not crash. Not sure what the problem is here.
child->aSkill = s;
child->parent = n;
n->children[i] = child;
return;
}
}
return;
}
for (int i = 0; i<CHILD_MAX; i++)
{
if (n->children[i] != NULL)
{
q.push(n->children[i]);
}
}
}
}
Skill Class
#include <iostream>
#include "Skill.h"
Skill::Skill()
{
name = NULL;
desc = NULL;
level = 0;
}
Skill::Skill(char* name, char* desc, int level) : level(level), name(new char[strlen(name) + 1]), desc(new char[strlen(desc) + 1])
{
strcpy_s(this->name, (strlen(name) + 1), name);
strcpy_s(this->desc, (strlen(desc) + 1), desc);
}
Skill::Skill(const Skill& aSkill)
{
this->name = new char[strlen(aSkill.name) + 1];
strcpy_s(this->name, (strlen(aSkill.name) + 1), aSkill.name);
this->level = aSkill.level;
this->desc = new char[strlen(aSkill.desc) + 1];
strcpy_s(this->desc, (strlen(aSkill.desc) + 1), aSkill.desc);
}
Skill& Skill::operator=(const Skill& aSkill)
{
if (this == &aSkill)
return *this;
else
{
delete[] name;
delete[] desc;
name = new char[strlen(aSkill.name) + 1];
strcpy_s(name, (strlen(aSkill.name) + 1), aSkill.name);
desc = new char[strlen(aSkill.desc) + 1];
strcpy_s(name, (strlen(aSkill.desc) + 1), aSkill.desc);
level = aSkill.level;
return *this;
}
}
Skill::~Skill()
{
delete[] name;
delete[] desc;
}
char* Skill::GetName() const
{
return name;
}
char* Skill::GetDesc() const
{
return desc;
}
int Skill::GetLevel() const
{
return level;
}
void Skill::Display(ostream& out)
{
out << "- " << GetName() << " -- " << GetDesc() << " [Lvl: " << GetLevel() << "]\n";
}
Node:
Skill aSkill;
Node* parent;
Node* children[CHILD_MAX];
Node() : parent(NULL)
{
for (int i = 0; i < CHILD_MAX; i++)
{
children[i] = NULL;
}
};
Node(const Skill& n) : aSkill(n), parent(NULL)
{
for (int i = 0; i < CHILD_MAX; i++)
{
children[i] = NULL;
}
};
Here is an extract from main()
SkillTree student("Student");
student.Display(cout);
student.AddSkill("Alphabet","Mastery of letters and sounds",0);
student.Display(cout);
student.AddSkill("Reading","The ability to read all manner of written material",1,"Alphabet");
student.AddSkill("Writing","The ability to put your thoughts on paper",1,"Alphabet");
student.Display(cout);
student.AddSkill("Speed Reading Level 1","Read any text twice as fast as normal",5,"Reading");
student.AddSkill("Speed Reading Level 2","Read any text four times as fast as normal",10,"Speed Reading Level 1");
student.AddSkill("Memorization","Memorize average sized texts",10,"Reading");
student.AddSkill("Massive Memorization","Memorize large sized texts",20,"Memorization");
student.AddSkill("Spell Writing","The ability to write spells",5,"Writing");
student.AddSkill("History","The ability to write (and rewrite) history",10,"Writing");
student.AddSkill("Written Creation","The ability to write things into reality",20,"History");
student.Display(cout);
The two functions that student.Display(cout); calls are as follow
void Tree::Display(ostream& out)
{
out << "Skill Tree: " << title << "\n";
if (this->root == NULL)
{
cout << "Empty\n";
return;
}
else
Display_r(out, this->root, 1);
}
void Tree::Display_r(ostream& out, Node* n, int depth)
{
for (int i = 0; i<depth; i++)
{
out << " ";
}
n->aSkill.Display(out);
for (int i = 0; i<CHILD_MAX; i++)
{
if (n->children[i] != NULL)
{
Display_r(out, n->children[i], depth + 1);
}
}
}
If I comment out a section of code in the Queue implementation of AddSkill(), I get no error.
In the first AddSkill() you insert the new node on the top of the tree, making it the new root.
In the second AddSkill() you intend to insert the new node as child of a parent skill. The approach seems to be:
check that there is at least one node in the tree (initial if)
traverse the tree to find the parrent node ( while loop )
if the parent is found, find the first empty child to insert the new skill (inner for loop)
What are the problems ?
THere are several flaws in your algorithm:
you loop on root not null. As the tree is not empty here, and as you don't delete any node, this condition will remain true, allowing for an endless loop.
then you check if the new child's name corresponds to the parentname. I assume that this will be false most of the case (otherwhise you'd need one parameter less). So this will ensure that the loop is endless.
later you assume that node is the current node, and you insert the new child into node's children. This code is not exectuted. Fortunately: it would be undefined behaviour, because you've set node to NULL and never changed this value.
How to solve it ?
To do this right, you'd have to start with node at root, then check if the node's name matches parentname, and if yes, insert the child as you did.
There's a last problem however. A rather important one. The structure of your algorithm works for a linked list traversal, but not a tree traversal. The tree traversal algorithm requires either a stack/list to keep track of all the branches to explore, or a recursive approach.
Here some code (sorry, I've replaced char* with string and used vector<Node*> instead of Node*[]), using an auxiliary overload of AddSkill(), to perform the recursive search:
// replaces the former one that you had
void Tree::AddSkill(string name, string desc, int level, string parentName)
{
if (root == NULL)
{
cout << "Error: no nodes in tree.\n";
return;
}
Skill s(name, desc, level);
AddSkill(root, s, parentName);
}
// auxiliary helper
void Tree::AddSkill(Node*node, Skill& s, string& parentName)
{
if (node->sk.name == parentName) { // if found, add the new node as childen
Node * child = new Node(s);
child->parent = node;
node->children.push_back(child);
}
else {
for (auto &x : node->children) // for all the children
AddSkill(x, s, parentName); // search recursively
}
}
And here an online demo using shared pointers instead of raw pointers.

Converting a Binary Tree to Double Threaded Binary Tree?

I could not find anything on search to satisfy my question, if it exists, I'm sorry!
I am working on a college assignment about threaded binary trees. I.e. various kinds of traversals - inorder, postorder and preorder on double TBT.
This is the TBTNode struct:
struct TBTNode {
TBTNode *left, *right, *parent;
char data;
bool left_normal, right_normal;
TBTNode(char d) {
data = d;
left = NULL;
right = NULL;
parent = NULL;
left_normal = true;
right_normal = true;
}
};
As you can see, there is not much distinction between a Binary Tree node and a TBT node, except that the node's properties, viz. {left,right}_normal are set to true when required.
To create the tree, I have this:
class TBT {
TBTNode *root;
public:
TBT() {
root = new TBTNode(0);
root->right = root;
root->right_normal = true;
cout << "Root:" ;
root->left = create();
if(root->left)
root->left_normal = true;
}
TBTNode* create();
};
TBTNode* TBT::create() {
char data;
TBTNode *node = NULL;
cout << endl << "Enter data (0 to quit): ";
cin >> data;
if(data == '0')
return NULL;
node = new TBTNode(data);
cout << endl << "Enter left child of " << data;
node->left = create();
if(node->left)
node->left->parent = node;
else {
node->left = root;
node->right = node->parent;
node->left_normal = node->right_normal = false;
}
cout << endl << "Enter right child of " << data;
node->right = create();
if(node->right)
node->right->parent = node;
else {
node->left = node;
node->right = node->parent->parent;
node->left_normal = node->right_normal = false;
}
return node;
}
After the tree gets recursively created using the above code, I want to convert it into a double threaded binary tree. I know the concept that left child is linked to the child's inorder predecessor and right to inorder successor, but I am unable to create an algorithm. Can someone help me?
I found the solution myself. First traverse the tree in inorder and add nodes to an array as you go on. Then process the array to link threads, because for a given element x in the array, the one previous to x will be inorder predecessor and one after x will be inorder successor. For the first and last element, special checks are made to link them to the head node (not root).
Parent link isn't needed, and it's removed.
Code is as follows:
class TBT {
TBTNode *root;
void createInorderArray(TBTNode *T);
TBTNode **array;
unsigned array_size;
public:
TBT();
TBTNode* create();
void inorder();
void preorder();
};
TBT::TBT() {
root = new TBTNode(0);
root->right = root;
root->right_normal = true;
cout << "Root:" ;
root->left = create();
if(!root->left) {
root->left_normal = false;
root->left = root;
}
array = NULL;
array_size = 0;
createInorderArray(root->left);
for(unsigned i = 0; i < array_size; i++) {
if(!array[i]->left) {
array[i]->left = i == 0 ? root : array[i-1];
array[i]->left_normal = false;
}
if(!array[i]->right) {
array[i]->right_normal = false;
array[i]->right = i == (array_size - 1) ? root : array[i+1];
}
}
free(array);
array_size = 0;
}
void TBT::createInorderArray(TBTNode *T) {
if(!T)
return;
createInorderArray(T->left);
array = (TBTNode**) realloc(array, sizeof(TBTNode**) * ++array_size);
array[array_size-1] = T;
createInorderArray(T->right);
}