Optimization for 8 puzzle solutions to store in trees structure - c++

I have a breadth first search to find the best solution to an 8 puzzle. In order to make sure I don't execute the same function call on the same puzzle move I have created a tree structure. It doesn't store the puzzle, just creates a pathway in the tree for the 9 values for the 9 slots in the puzzle. Here is the code:
static const int NUM_NODES = 9;
class TreeNode
{
public:
TreeNode *mylist[NUM_NODES];
TreeNode()
{
for (int x = 0; x < NUM_NODES; ++x)
mylist[x] = nullptr;
}
};
class Tree
{
private:
TreeNode *mynode;
public:
Tree()
{
mynode = new Node();
}
bool checkOrCreate(const Puzzle &p1)
{
Node *current_node = mynode;
bool found = true;
for (int x = 0; x < PUZZLE_SIZE; ++x)
{
for (int y = 0; y < PUZZLE_SIZE; ++y)
{
int index_value = p1.grid[x][y];
if (current_node->mylist[index_value] == nullptr)
{
found = false;
current_node->mylist[index_value] = new Node();
current_node = current_node->mylist[index_value];
}
else
current_node = current_node->mylist[index_value];
}
}
return found;
}
};
static Node* depth_Limited_Search(Problem &problem, int limit)
{
mylist.reset();
return recursive_Depth_Search(&Node(problem.initial_state, nullptr, START), problem, limit);
}
static Node *recursive_Depth_Search(Node *node, Problem &problem, int limit)
{
if (problem.goal_state == node->state)
return node;
else if (limit == 0)
return nullptr;
if (mylist.checkOrCreate(node->state)) //if state already exists, delete the node and return nullptr
return nullptr;
std::unique_ptr<int> xy(node->state.getCoordinates());
int xOfSpace = xy.get()[0];
int yOfSpace = xy.get()[1];
set <Action> actions = problem.actions(node->state); //gets actions
for (auto it = begin(actions); it != end(actions); ++it)
{
Action action = *it;
Node &child = child_node(problem, *node, action);
Node *answer = recursive_Depth_Search(&child, problem, limit - 1);
if (answer != nullptr)
return answer;
}
return nullptr;
}
static Node& child_node(Problem problem, Node &parent, Action action)
{
Node &child = *(new Node());
child.state = problem.result(parent.state, action);
child.parent = &parent;
child.action = action;
child.path_cost = parent.path_cost + problem.step_cost(parent.state, action);
return child;
}
Puzzle& result(const Puzzle &state, Action action)
{
// return a puzzle in the new state after perfroming action
Puzzle &new_state = *(new Puzzle(state));
int r = state.getCoordinates()[0], c = state.getCoordinates()[1];
if (action == UP)
new_state.swap(r, c, r - 1, c);
else if (action == RIGHT)
new_state.swap(r, c, r, c + 1);
else if (action == DOWN)
new_state.swap(r, c, r + 1, c);
else if (action == LEFT)
new_state.swap(r, c, r, c - 1);
return new_state;
}
I've used this on breadth and also on depth limited search using recursion to solve. Using this structure to store all the possible solutions for these algorithms takes a long time. I believe it has something to do with the allocation taking time. Is that the reason? I was thinking of trying to just create a lump of memory, and then assigning a node that address of memory instead of letting the program do it. Would that be the best solution, and how would I do that? (Since I've used this on multiple searches and they all take a long time to perform I haven't included that code.)

Related

Function couldn't been resolved

I have a problem with my C++ code. It says that the all the functions starting with isPerfectRec() couldn't be resolved...Why? I tried a lot of things but apparently they don't work. I have a lot of assigments like to verify if the binary search tree is perfect, to find the second largest element in a binary search tree and so on..
#include <stdio.h>
#include<iostream>
#include<stack>
template<typename T> class BinarySearchTree {
public:
BinarySearchTree<T> *root, *left_son, *right_son, *parent;
T *pinfo;
BinarySearchTree() {
left_son = right_son = NULL;
root = this;
pinfo = NULL;
}
void setInfo(T info) {
pinfo = new T;
*pinfo = info;
}
void insert(T x) {
if (pinfo == NULL)
setInfo(x);
else
insert_rec(x);
}
bool isPerfectRec(BinarySearchTree *root, int d, int level = 0)
{
// An empty tree is perfect
if (*root == NULL)
return true;
// If leaf node, then its depth must be same as
// depth of all other leaves.
if (*root->left_son == NULL && root->*right_son == NULL)
return (d == level+1);
// If internal node and one child is empty
if (root->*left_son == NULL || root->*right_son == NULL)
return false;
// Left and right subtrees must be perfect.
return isPerfectRec(root->*left_son, d, level+1) &&
isPerfectRec(root->*right_son, d, level+1);
}
// Wrapper over isPerfectRec()
bool isPerfect(BinarySearchTree *root)
{
int d = findADepth(root);
return isPerfectRec(root, d);
}
int findADepth(BinarySearchTree *node)
{
int d = 0;
while (node != NULL)
{
d++;
node = node->left_son;
}
return d;
}
// A function to find 2nd largest element in a given tree.
void secondLargestUtil(BinarySearchTree *root, int &c)
{
// Base cases, the second condition is important to
// avoid unnecessary recursive calls
if (root == NULL || c >= 2)
return;
// Follow reverse inorder traversal so that the
// largest element is visited first
secondLargestUtil(root->right_son, c);
// Increment count of visited nodes
c++;
// If c becomes k now, then this is the 2nd largest
if (c == 2)
{
std::cout << "2nd largest element is "
<< root->pinfo;
printf("\n___\n");
return;
}
// Recur for left subtree
secondLargestUtil(root->left_son, c);
}
void secondLargest(BinarySearchTree *root)
{
// Initialize count of nodes visited as 0
int c = 0;
// Note that c is passed by reference
secondLargestUtil(root, c);
}
bool hasOnlyOneChild(int pre[], int size)
{
int nextDiff, lastDiff;
for (int i=0; i<size-1; i++)
{
nextDiff = pre[i] - pre[i+1];
lastDiff = pre[i] - pre[size-1];
if (nextDiff*lastDiff < 0)
return false;;
}
return true;
}
BinarySearchTree * readListInter(){
BinarySearchTree* root = NULL;//returning object
BinarySearchTree* temp;
BinarySearchTree* input;//new node to add
int x;
std::cout << "enter number (>0 to stop): ";
std::cin >> x;
while(x>=0){
input = BinarySearchTree(x);
if(root == NULL){//if root is empty
root = input;
temp = root;//temp is use to store value for compare
}
else{
temp = root; //for each new addition, must start at root to find correct spot
while(input != NULL){
if( x < temp->pinfo){//if smaller x to add to left
if(temp->left_son == NULL){//left is empty
temp->left_son = input;
input = NULL;//new node added, exit the loop
}
else{//if not empty set temp to subtree
temp = temp->left_son;//need to move left from the current position
}
}
else{//otherwise x add to right
if(temp->right_son == NULL){//right is empty
temp->right_son = input;
input = NULL;//new node added, exit the loop
}
else{
temp = temp->right_son;//need to move right from the current position
}
}
}
}
std::cin >> x;
}
return root;
}
};
int main() {
BinarySearchTree<int> *r = new BinarySearchTree<int>;
BinarySearchTree<int> *r1 = new BinarySearchTree<int>;
BinarySearchTree<int> *p = new BinarySearchTree<int>;
p = readListInter();
r->insert(6);
r->insert(8);
r->insert(1);
r->insert(9);
r->insert(10);
r->insert(4);
r->insert(13);
r->insert(12);
printf("\n___\n");
r1->insert(6);
r1->insert(8);
r1->insert(1);
r1->insert(9);
r1->insert(10);
r1->insert(4);
r1->insert(13);
r1->insert(12);
printf("\n___\n");
r->isPerfect(r);
int pre[] = {8, 3, 5, 7, 6};
int size = sizeof(pre)/sizeof(pre[0]);
if (hasOnlyOneChild(pre, size) == true )
printf("Yes");
else
printf("No");
s
return 0;
}
I think you need to write BinarySearchTree<T> instead of BinarySearchTree as a datatype in those functions.

Inserting element into left leaning black red tree c++

I have been staring at this all day and have gotten slightly somewhere, but it's still not working correctly! Just trying to 'put' (really insert, or find if it's there) an element k into a LL red black tree. Here's my method:
Node * RPut(Node* p, const K& k, Node*& location)
{
// if you are at the bottom of the tree,
// add new node at bottom of the tree
if (p == 0)
{
// new red note with new data
location = NewNode(k, Data(), RED);
return location;
}
if(greater_(k,p->key_))
{
// if it's greater than the root, move down to the left child
p->left_ = Rput(p->left_, k, location);
}
// right subtree
else if (greater_(p->key_,k))
{
// but if the key is less than root, move down to right child
p->right_ = Rput(p->right_, k, location);
}
// if they are equal
else
{
location = p;
}
// code for rotating
// this sort of worked.
if(p->right_ && p->right_->IsRed())
{
p = RotateLeft(p);
if (p->left_->IsBlack())
{
p->SetBlack();
p->left_->SetRed();
}
}
if (p->left_ && p->left_->IsRed())
{ if (p->left_->left_ && p->left_->left_->IsRed())
{
p = RotateRight(p);
p->left_->SetBlack();
p->right_->SetBlack();
}
}
return p;
}
I know my rotate methods work perfectly. This inserts correctly until the fifth element (I haven't tried every combination, but usually.) For instance, abcde inserted correctly would be
d
b e
a c --
[with b as red node]
mine works but stops here, giving me:
b
a d
- - c e
with NO red nodes.
Anyone see anything obvious I am overlooking or why it isn't working properly? Any help at all much appreciated.
Thanks!
This does not directly answer the question, but have you read Sedgewick's paper on left-leaning red black trees? The code in it is exceptionally clear, there are beautiful diagrams explaining how things work, and, I imagine, it would be straight-forward to reimplement everything into C++.
Edit
I tried, for fun to implement Sedgewick's code. It turns out the paper had a few methods/subroutines left out that would have been pretty helpful to include. Anyway, my C++11 implementation, along with some tests, follows.
Since Java does automagic memory management, Sedgewick doesn't explicitly note where memory should be freed in his code. Rather than try to figure this out for a quick project and possibly leave memory leaks, I've opted to use std::shared_ptr, which provides a similar worry-free behaviour.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <memory>
template<class keyt, class valuet>
class LLRB {
private:
static const bool COLOR_RED = true;
static const bool COLOR_BLACK = false;
class Node {
public:
keyt key;
valuet val;
std::shared_ptr<Node> right;
std::shared_ptr<Node> left;
bool color;
Node(keyt key, valuet val){
this->key = key;
this->val = val;
this->color = COLOR_RED;
this->right = nullptr;
this->left = nullptr;
}
};
typedef std::shared_ptr<Node> nptr;
nptr root;
nptr rotateLeft(nptr h){
nptr x = h->right;
h->right = x->left;
x->left = h;
x->color = h->color;
h->color = COLOR_RED;
return x;
}
nptr rotateRight(nptr h){
nptr x = h->left;
h->left = x->right;
x->right = h;
x->color = h->color;
h->color = COLOR_RED;
return x;
}
nptr moveRedLeft(nptr h){
flipColors(h);
if(isRed(h->right->left)){
h->right = rotateRight(h->right);
h = rotateLeft(h);
flipColors(h);
}
return h;
}
nptr moveRedRight(nptr h){
flipColors(h);
if(isRed(h->left->left)){
h = rotateRight(h);
flipColors(h);
}
return h;
}
void flipColors(nptr h){
h->color = !h->color;
h->left->color = !h->left->color;
h->right->color = !h->right->color;
}
bool isRed(const nptr h) const {
if(h==nullptr) return false;
return h->color == COLOR_RED;
}
nptr fixUp(nptr h){
if(isRed(h->right) && !isRed(h->left)) h = rotateLeft (h);
if(isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);
if(isRed(h->left) && isRed(h->right)) flipColors (h);
return h;
}
nptr insert(nptr h, keyt key, valuet val){
if(h==nullptr)
return std::make_shared<Node>(key,val);
if (key == h->key) h->val = val;
else if(key < h->key) h->left = insert(h->left, key,val);
else h->right = insert(h->right,key,val);
h = fixUp(h);
return h;
}
//This routine probably likes memory
nptr deleteMin(nptr h){
if(h->left==nullptr) return nullptr;
if(!isRed(h->left) && !isRed(h->left->left))
h = moveRedLeft(h);
h->left = deleteMin(h->left);
return fixUp(h);
}
nptr minNode(nptr h){
return (h->left == nullptr) ? h : minNode(h->left);
}
//This routine leaks memory like no other!! I've added a few cleanups
nptr remove(nptr h, keyt key){
if(key<h->key){
if(!isRed(h->left) && !isRed(h->left->left))
h = moveRedLeft(h);
h->left = remove(h->left, key);
} else {
if(isRed(h->left))
h = rotateRight(h);
if(key==h->key && h->right==nullptr)
return nullptr;
if(!isRed(h->right) && !isRed(h->right->left))
h = moveRedRight(h);
if(key==h->key){
std::shared_ptr<Node> mn = minNode(h->right);
h->val = mn->val;
h->key = mn->key;
h->right = deleteMin(h->right);
} else {
h->right = remove(h->right, key);
}
}
return fixUp(h);
}
void traverse(const nptr h) const {
if(h==nullptr)
return;
traverse(h->left);
std::cout<< h->key << "=" << h->val <<std::endl;
traverse(h->right);
}
public:
LLRB(){
root = nullptr;
}
void traverse() const {
traverse(root);
}
valuet search(keyt key){
nptr x = root;
while(x!=nullptr){
if (key == x->key) return x->val;
else if (key < x->key) x=x->left;
else x=x->right;
}
return keyt();
}
void insert(keyt key, valuet val){
root = insert(root,key,val);
root->color = COLOR_BLACK;
}
void remove(keyt key){
root = remove(root,key);
root->color = COLOR_BLACK;
}
};
int main(){
for(int test=0;test<500;test++){
LLRB<int,int> llrb;
std::vector<int> keys;
std::vector<int> vals;
for(int i=0;i<1000;i++){
//Ensure each key is unique
int newkey = rand();
while(llrb.search(newkey)!=int())
newkey = rand();
keys.push_back(newkey);
vals.push_back(rand()+1);
llrb.insert(keys.back(),vals.back());
}
//llrb.traverse();
for(int i=0;i<1000;i++){
if(llrb.search(keys[i])!=vals[i]){
return -1;
}
}
for(int i=0;i<500;i++)
llrb.remove(keys[i]);
for(int i=500;i<1000;i++){
if(llrb.search(keys[i])!=vals[i]){
return -1;
}
}
}
std::cout<<"Good"<<std::endl;
}

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.

C++ find largest BST in a binary tree

what is your approach to have the largest BST in a binary tree? with largest, i mean: highest.
I refer to this post where a very good implementation for finding if a tree is
BST or not is
bool isBinarySearchTree(BinaryTree * n,
int min=std::numeric_limits<int>::min(),
int max=std::numeric_limits<int>::max())
{
return !n || (min < n->value && n->value < max
&& isBinarySearchTree(n->l, min, n->value)
&& isBinarySearchTree(n->r, n->value, max));
}
It is quite easy to implement a solution to find whether a tree contains a binary search tree. i think that the following method makes it:
bool includeSomeBST(BinaryTree* n)
{
return includeSomeBST(n->left) || includeSomeBST(n->right) ;
if(n == NULL)
return false ;
return true ;
}
but what if i want the largest BST? this is my first idea,
BinaryTree largestBST(BinaryTree* n)
{
if(isBinarySearchTree(n))
return n;
if(!isBinarySearchTree(n->left))
{
if(!isBinarySearchTree(n->right))
if(includeSomeBST(n->right))
return largestBST(n->right);
else if(includeSomeBST(n->left))
return largestBST(n->left);
else
return NULL;
else
return n->right;
}
else
return n->left;
}
but its not telling the largest actually. i struggle to make the comparison. how should it take place?
thanks
Yes,your function includeSomeBST is wrong. You just check the nodes n,n->left and n->right, but you must check the nodes recursively.
bool includeSomeBST(BinaryTree* n)
{
if(!isBinarySearchTree(n))
{
return includeSomeBST(n->left) || includeSomeBST(n->right);
}
if(n==NULL) return false;
return true;
}
Here is a successful code implementation for the same along with the driver program:
#include <iostream>
using namespace std;
class BinaryTree {
public:
BinaryTree *right;
BinaryTree *left;
int value;
BinaryTree(int value) {
this->value = value;
}
};
int max_value(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
int min_value(int a, int b) {
if (a < b) {
return a;
} else {
return b;
}
}
BinaryTree* findLargestBST(BinaryTree *n, int* maxSize, int *max, int *min, bool *is_bst) {
if (n == NULL) {
*maxSize = 0;
*is_bst = true;
return n;
}
int *lc_max_size = new int;
int *rc_max_size = new int;
int *lc_max = new int;
int *lc_min = new int;
int *rc_max = new int;
int *rc_min = new int;
*lc_max = std::numeric_limits<int>::min();
*rc_max = *lc_max;
*lc_min = std::numeric_limits<int>::max();
*rc_min = *lc_min;
BinaryTree* returnPointer;
bool is_curr_bst = true;
BinaryTree* lc = findLargestBST(n->left, lc_max_size, lc_max, lc_min, is_bst);
if (!*is_bst) {
is_curr_bst = false;
}
BinaryTree* rc = findLargestBST(n->right, rc_max_size, rc_max, rc_min, is_bst);
if (!*is_bst) {
is_curr_bst = false;
}
if (is_curr_bst && *lc_max <= n->value && n->value <= *rc_min) {
*is_bst = true;
*maxSize = 1 + *lc_max_size + *rc_max_size;
returnPointer = n;
*max = max_value (n->value, *rc_max);
*min = min_value (n->value, *lc_min);
} else {
*is_bst = false;
*maxSize = max_value(*lc_max_size, *rc_max_size);
if (*maxSize == *lc_max_size) {
returnPointer = lc;
} else {
returnPointer = rc;
}
*max = *min = n->value;
}
delete lc_max_size;
delete rc_max_size;
delete lc_max;
delete lc_min;
delete rc_max;
delete rc_min;
return returnPointer;
}
int main() {
/* Let us construct the following Tree
50
/ \
10 60
/ \ / \
5 20 55 70
/ / \
45 65 80
*/
BinaryTree *root = new BinaryTree(50);
root->left = new BinaryTree(10);
root->right = new BinaryTree(60);
root->left->left = new BinaryTree(5);
root->left->right = new BinaryTree(20);
root->right->left = new BinaryTree(55);
root->right->left->left = new BinaryTree(45);
root->right->right = new BinaryTree(70);
root->right->right->left = new BinaryTree(65);
root->right->right->right = new BinaryTree(80);
/* The complete tree is not BST as 45 is in right subtree of 50.
The following subtree is the largest BST
60
/ \
55 70
/ / \
5 65 80
*/
int *maxSize = new int;
int *min_value = new int;
int *max_value = new int;
*min_value = std::numeric_limits<int>::max();
*max_value = std::numeric_limits<int>::min();
bool *is_bst = new bool;
BinaryTree *largestBSTNode = findLargestBST(root, maxSize, max_value, min_value, is_bst);
printf(" Size of the largest BST is %d", *maxSize);
printf("Max size node is %d", largestBSTNode->value);
delete maxSize;
delete min_value;
delete max_value;
delete is_bst;
getchar();
return 0;
}
The approach used is fairly straightforward and can be understood as follows:
It is a bottom to top approach instead of a top to bottom one which we use when determining whether the tree is a BST or not. It uses the same max-min approach used while determining the tree as a BST or not.
Following are the steps which are executed at each of the nodes in a recursive fashion:
Note: Please remember that this is a bottom up approach and the information is going to flow from the bottom to the top.
1) Determine whether I am existent or not. If I am not (I am null) I should not influence the algorithm in any way and should return without doing any modifications.
2) At every node, maximum size of the BST till this point is stored. This is determined using the total size of the left subtree + the total size of the right subtree + 1(for the node itself) if the tree at this particular node satisfies the BST property. Otherwise, it is figured out from the max values that have been returned from the left subtree and the right subtree.
3) In the case if the BST property is satisfied at the given node then the current node is returned as the maximum size BST till this point otherwise it is determined from the left and the right subtrees.

Node does not name a type error

I have searched through the other questions and none of them seem to apply
exactly.
I am writing a program that finds a route through a maze,
the only real thing im having a problem with is this one compiler error.
It has to do with the one function I have the returns a Node ( struct).
Header file: (I cut the define stuff off)
#include <iostream>
#include <string>
using namespace std;
class Graph {
private:
struct Node {
int id; //int id
Node * north; //north path node
Node * south; //south path node
Node * east; //east path node
Node * west; //went path node
bool visited; // visited bool
};
//this struct holds the path that is found.
struct Elem {
int id; //The id of the node
string last; //the door that it passed through
Elem * back; //back one path
Elem * next; //forward one path
};
//This is a graph with a very smart struct
//This is the main node that makes up the graph.
Node * start;
Node ** initArr;
int arrLen;
Elem * head;
Elem * tail;
int path;
public:
Graph();
//Constructs empty graph
Graph(const Graph &v);
//copy constructor
~Graph();
//destructor
Graph & operator = (const Graph &v);
//assignment operator
void output(ostream & s) const;
//Prints the graph
void input(istream & s);
//input and creates the graph
Node * find(int id);
//finds the node in the graph
void makePath();
//makes a path through the maze
bool findPath(Node* cur, string room);
//worker function for recursion
void pathOut(ostream & s) const;
//Outputs the found path
void removeTail();
//Removes the last element
void addTail(Node* n, string door);
//Adds the element to the tail
//Mutators
void setId(Node* n ,int x);
void setVisited(Node* n, bool v);
//Elem Mutator
void seteId(Elem* e, int x);
//Elem Accessor
int geteId(Elem* e);
//Accessors
int getId(Node* n);
bool getVisited(Node* n);
};
And my actual code file.
#include <iostream>
#include "graph.h"
using namespace std;
//Constructs empty graph
Graph::Graph()
{
start = 0;
head = tail = 0;
path = 0;
}
//copy constructor
Graph::Graph(const Graph &v)
{
//not implemented
}
//destructor
Graph::~Graph()
{
for(int i = 0; i < arrLen + 1; i++)
{
delete initArr[i];
}
while(head != 0)
{
Elem* p = head;
head = head->next;
delete p;
}
delete[] initArr;
}
//assignment operator
Graph & Graph::operator = (const Graph &v)
{
//not implemented
}
//Prints the graph
void Graph::output(ostream & s) const
{
s<<"Node"<<'\t'<<"North"<<'\t'<<"East"<<'\t'<<"South"<<'\t'<<"West"<<'\n';
for(int i = 1; i < arrLen + 1; i++)
{
Node* temp = initArr[i];
s<<temp->id<<'\t';
if(temp->north != 0)
s<<temp->north->id<<'\t';
else
s<<"--"<<'\n';
if(temp->east != 0)
s<<temp->east->id<<'\t';
else
s<<"--"<<'\n';
if(temp->south != 0)
s<<temp->south->id<<'\t';
else
s<<"--"<<'\n';
if(temp->west != 0)
s<<temp->west->id<<'\t';
else
s<<"--"<<'\n';
s<<'\n';
}
}
//input and creates the graph
void Graph::input(istream & s)
{
int length = 0;
s>>length;
arrLen = length;
if(s)
{
//define array
initArr = new Node*[length + 1];
int temp = 0;
for(int i = 1; i < length + 1; i++)
{
//Create node
s>>temp;
Node* n = new Node;
n->id = temp;
n->visited = false;
//Add to array
initArr[i] = n;
}
//Make Exit Node
Node *x = new Node;
x->id = 0;
x->visited = false;
initArr[0] = x;
//Loop through all of the node input
int tn = 0;
for(int f = 0; f < length; f++)
{
//Set Pointers
s>>tn;
Node* curNode = find(tn);
int n = 0;
int e = 0;
int st = 0;
int w = 0;
s>>n>>e>>st>>w;
curNode->north = find( n );
curNode->east = find( e );
curNode->south = find( st );
curNode->west = find( w );
}
//set Entry point to graph
int last = 0;
s>>last;
start = find(last);
}
}
//finds the node in the array
Node* Graph::find(int id)
{
if( id == 0)
{
return initArr[0];
}
if(id == -1)
{
return 0;
}
else
{
for(int i = 1; i < arrLen + 1; i++)
{
if(initArr[i]->id == id)
{
return initArr[i];
}
}
cerr<<"NOT FOUND IN GRAPH";
return 0;
}
}
//makes a path through the maze
void Graph::makePath()
{
if(findPath(start->north, "north") == true)
{
path = 1;
return;
}
else if( findPath(start->east, "east") == true)
{
path = 1;
return;
}
else if( findPath(start->south, "south") == true)
{
path = 1;
return;
}
else if( findPath(start->west, "west") == true)
{
path = 1;
return;
}
return;
}
//finds a path to the outside
bool Graph::findPath(Node* cur, string room)
{
addTail(cur, room);
if(cur = initArr[0])
{
return true;
}
if(cur->north != 0 && cur->north->visited == false)
{
cur->visited = true;
findPath(cur->north, "north");
}
else if(cur->east != 0 && cur->east->visited == false)
{
cur->visited = true;
findPath(cur->north, "east");
}
else if(cur->south !=0 && cur->south->visited == false)
{
cur->visited = true;
findPath(cur->north, "south");
}
else if(cur->west != 0 && cur->west->visited == false)
{
cur->visited = true;
findPath(cur->north, "west");
}
else
{
cur->visited = false;
removeTail();
}
}
//Outputs the found path
void Graph::pathOut(ostream & s) const
{
if(path == 1)
{
Elem *p;
p = head->next;
while(p != 0)
{
s<<p->id<<"--> "<<p->last;
p= p->next;
}
}
else if(path == 0)
{
}
}
//Removes the last element in the chain
void Graph::removeTail()
{
Elem* temp = 0;
temp = tail;
tail = tail->back;
delete temp;
}
//Adds the element to the tail
void Graph::addTail(Node* n, string door)
{
if(head != 0)
{
Elem* temp = new Elem;
temp->id = n->id;
tail->next = temp;
tail->last = door;
temp->back = tail;
temp->next = 0;
tail = 0;
}
else
{
Elem *p = new Elem;
p->last = "";
p->back = 0;
p->next = 0;
head = p;
tail = p;
}
}
//Mutators
void Graph::setId(Node *n ,int x)
{
n->id = x;
}
void Graph::setVisited(Node *n, bool v)
{
n->visited = v;
}
//Elem Mutator
void Graph::seteId(Elem *e, int x)
{
e->id = x;
}
//Elem Accessor
int Graph::geteId(Elem *e)
{
return e->id;
}
//Accessors
int Graph::getId(Node *n)
{
return n-> id;
}
bool Graph::getVisited(Node *n)
{
return n->visited;
}
/*
//This is a graph with a very smart struct
//This is the main node that makes up the graph.
struct Node {
int id; //int id
Node *north; //north path node
Node *south; //south path node
Node *east; //east path node
Node *west; //went path node
bool visited; // visited bool
};
//this struct holds the path that is found.
struct Elem {
int id; //The id of the node
string last; //the door that it passed through
Elem* back; //back one path
Elem* next; //forward one path
};
Node* Start;
Node ** initArr;
Elem* head;
Elem* tail;
*/
//outputs using named operation
ostream & operator << (ostream &s, const Graph & v)
{
v.output(s);
return s;
}
The error is occurring on the find function.
In the cpp file, Node is not in global scope. It's nested inside Graph as such, you need to qualify it in a return type:
Graph::Node* Graph::find(int id){
// ...
}
Inside the function, you're in the scope of Graph again, as such you do not need to qualify it.
You have both Node and Element defined as structs inside the class Graph. It would be better to define them outside the class Graph. You can define a separate Node class and store the element struct as its private members. The error happens because Node is a private member of Graph, which can be accessed as Graph::Node. E.g. Graph::Node* find(...).