I am really stuck, I'm getting an error at "CTree.add(num);" saying 'CTree' is undeclared, which doesn't make sense because I initialized it in tree.h?
The program is supposed to prompt the user, the user enters a command (i.e. "add 3", only 0-9 integers) and then I want it to insert that number into the tree.
//File: tree.h
class CTree
{
private:
CTree* m_pLeft;
CTree* m_pRight;
CTree* m_pRoot;
int m_nData;
public:
CTree();
bool isEmpty() const { return m_pRoot; }
bool search(int);
void print_inorder();
void inorder(CTree*);
void Add(int);
void remove(int);
void height();
};
//File: CTree.cpp
#include <iostream>
#include <cstdlib>
using namespace std;
CTree::CTree()
{
m_pRoot=NULL;
}
bool CTree::search(int x)
{
if(x==m_nData) return true;
if(x < m_nData){ //go left
if(m_pLeft != NULL) //if possible
return m_pLeft->search(x);
}
else //go right
if(m_pRight != NULL) //ifpossible
return m_pRight->search(x);
return false;
}
void CTree::Add(int x)
{
CTree* t = new CTree;
CTree* parent;
t->m_nData = x;
t->m_pLeft = NULL;
t->m_pRight = NULL;
parent = NULL;
if(isEmpty()) m_pRoot = t;
else
{
//insert leaf nodes
CTree* leaf;
leaf = m_pRoot;
// find parent
while(leaf)
{
parent = leaf;
if(t->m_nData > leaf->m_nData)
leaf = leaf->m_pRight;
else
leaf = leaf->m_pLeft;
}
if(t->m_nData < parent->m_nData)
parent->m_pLeft = t;
else
parent->m_pRight = t;
}
}
void CTree::remove(int x)
{
bool found = false;
if(isEmpty())
{
cout<< "Tree is empty!" <<endl;
return;
}
CTree* current;
CTree* parent;
current = m_pRoot;
while(current != NULL)
{
if(current->m_nData == x)
{
found = true;
break;
}
else
{
parent = current;
if(x > current->m_nData) current = current->m_pRight;
else current = current->m_pLeft;
}
}
if(!found)
{
cout<< "Not found!" <<endl;
return;
}
// Node with single child
if((current->m_pLeft == NULL && current->m_pRight != NULL)|| (current->m_pLeft != NULL&& current->m_pRight != NULL))
{
if(current->m_pLeft == NULL && current->m_pRight != NULL)
{
if(parent->m_pLeft == current)
{
parent->m_pLeft = current->m_pRight;
delete current;
}
else
{
parent->m_pRight = current->m_pRight;
delete current;
}
}
else // left child present, no right child
{
if(parent->m_pLeft == current)
{
parent->m_pLeft = current->m_pLeft;
delete current;
}
else
{
parent->m_pRight = current->m_pLeft;
delete current;
}
}
return;
}
//We're looking at a leaf node
if( current->m_pLeft == NULL && current->m_pRight == NULL)
{
if(parent->m_pLeft == current) parent->m_pLeft = NULL;
else parent->m_pRight = NULL;
delete current;
//Node with 2 children
// replace node with smallest value in right subtree
if (current->m_pLeft != NULL && current->m_pRight != NULL)
{
CTree* check;
check = current->m_pRight;
if((check->m_pLeft == NULL) && (check->m_pRight == NULL))
{
current = check;
delete check;
current->m_pRight = NULL;
}
else // right child has children
{
//if the node's right child has a left child
// Move all the way down left to locate smallest element
if((current->m_pRight)->m_pLeft != NULL)
{
CTree* lcurrent;
CTree* lcurrent_parent;
lcurrent_parent = current->m_pRight;
lcurrent = (current->m_pRight)->m_pLeft;
while(lcurrent->m_pLeft != NULL)
{
lcurrent_parent = lcurrent;
lcurrent = lcurrent->m_pLeft;
}
current->m_nData = lcurrent->m_nData;
delete lcurrent;
lcurrent_parent->m_pLeft = NULL;
}
else
{
CTree* tmp;
tmp = current->m_pRight;
current->m_nData = tmp->m_nData;
current->m_pRight = tmp->m_pRight;
delete tmp;
}
}
return;
}
}
}
void CTree::print_inorder()
{
inorder(m_pRoot);
}
void CTree::inorder(CTree* x)
{
if(x != NULL)
{
if(x->m_pLeft) inorder(x->m_pLeft);
cout<<" "<<x->m_nData<<" ";
if(x->m_pRight) inorder(x->m_pRight);
}
else return;
}
//File: main.cpp
#include <iostream>
#include <cstdlib>
#include <sstream>
#include <locale>
#include <string>
#define PROMPT "bst> "
using namespace std;
int getNumber(string s)
{
int num;
for(int i; i<=s.length();i++)
{
if(isdigit(s[i]))
{
num= s[i]-48;
}
}
return num;
} // getNumber
bool process(const string& s, CTree* aTree)
{
bool mustquit=false;
int num;
istringstream iss(s);
do
{
string sub;
iss >> sub; //
if(sub=="add" || sub=="insert")
{
num=getNumber(s);
cout<<num<<endl;
aTree->Add(num);
}
else if(sub=="delete" || sub=="remove")
{
num=getNumber(s);
cout<<num<<endl;
}
else if(sub=="search" || sub=="find")
{
num=getNumber(s);
cout<<num<<endl;
}
else if(sub=="height")
{
//do stuff
}
else if (sub=="quit")
return mustquit;
//else cout<<"INPUT ERROR"<<endl;
} while (iss);
return mustquit;
}// process
int main(){
string input="";
CTree *myTree;
myTree = new CTree();
bool finished=false;
int i;
cout<<PROMPT;
while(!finished)
{
if(input!="")cout<<PROMPT;
getline(cin,input);
finished=process(input, myTree);
delete myTree;
}//while
return 0;
}
add is a non-static member function, which means you can only call it on an instance of CTree. e.g.
CTree myTree;
myTree.add(num);
You are aware that you need an instance of the class CTree to actually use it? You wrote the entire thing under the assumption that you're operating on an instance of a class. An actual tree, rather than a blueprint for it.
As the answer before me said, it's not a static function or class-level. A non-static method needs to be invoked on an instance so that a silent pointer this can be set to something meaningful, ie. the actual instance you're working with - in this case adding a node.
ADDENDUM
(everything below works without modifying your code, just an explicit answer to your question, to make it compile. From a "working standpoint", this program is far from complete. Some pieces don't even make sense, many variables are left unused or uninitialized (and then used). Let me elaborate further below.)
What you need to do is this add this in your main where the old process() call occured:
CTree myTree; // you could also add (), even though it's a default constructor
finished=process(input, myTree);
And modify the function process' argument list to include a reference to your tree which you wish to operate on. This is just one of the possibilities, you can also take a pointer etc. But a reference is cleaner:
bool process(const string& s, CTree& aTree)
Also, pay attention to compiler warnings. Good practice is to take care of all of them. And remember, this makes it compile, not work. It seems unfinished and rough around the edges.
And remember the difference between a class (an idea) and an instance (a manifestation of that idea). The technical details are not important right now, just make sure you have an instance to work with, as your class design intends. It seems to me that you don't have a grasp around how computer software works, how data and instructions that operate on it connect, especially from a viewpoint of memory. It's not enough for the computer to know what you want to do, it needs to know on what do you want the operations performed (which variables or objects or what-have-you). You can copy by value and return, do it in the main function, pass a reference or a pointer with an address so it can know where in memory is your object/instance located etc. If you're just experimenting, you could create a global instance. A lot of options.
Redeclaring everything doesn't carry over the changes that happen previously (since stuff goes out of scope). Nor does it make sense to call non-static member methods on the class level - and not even properly.
Hope it helps and happy coding. Keep at it, nothing worth doing is simple.
I think they are getting a little too technical for your level of experience. YourCTree class code creates what a CTree class is and how it behaves (a blueprint) but you actually have to tell your code to construct one and then have a way to reference it.
You can declare a stack variable instance like this:
CTree myTree;
This allocates the memory for your class and calls the constructor on entry into the function. You would then work with it by referencing the functions from the instance name using dot notation.
myTree.Add(4);
Or you can declare a pointer to a CTree and create a dynamic instance using the new operator
CTree *myTree;
myTree = new CTree();
Then you reference the tree using pointer notation:
myTree->Add(4);
if you do it that way you will need to delete the memory you allocated
delete myTree;
So in summary, a class definition of the kind you show here describes a class, but does not create one (allocate memory and setup pointers to the method code). This allows you to have many trees if your code logic requires them;
CTree directoryTree;
CTree fileTree;
CTree indexTree;
These would each have their own data ...
Good luck,
Related
This question already has answers here:
Warning of "Control may reach end of non-void function"
(3 answers)
Closed 1 year ago.
I was coding a BST Tree, and first i made it with integer key, everything worked fine. Then i copied my code and made some changes, i switched integer key to string key and also added one new pointer (because my goal is to create two trees, one with English words and one with their Polish translation) so i tested it just on single tree with string key first and insert function works fine like in the interger tree, but search function is returning some garbage insted of NULL or pointer to node. I dont really know what is a problem here.
I put the code of Integer tree below:
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
using namespace std;
typedef struct BST
{
int key;
BST* right;
BST* left;
}BST_node;
BST_node* CreateNewNode(int data) // function that returns new node of my tree
{
BST_node* NewNode = new BST_node;
NewNode->key = data;
NewNode->right = NULL;
NewNode->left = NULL;
return NewNode;
}
BST_node* bstSearch(BST_node* root, int data) // search function
{
if (root == NULL)
return NULL;
else if (root->key == data)
return root;
else if (root->key < data)
bstSearch(root->right, data);
else
bstSearch(root->left, data);
}
void bstInsert(BST_node*& root, int data) // insert function
{
if (root == NULL)
root = CreateNewNode(data);
if (data < root->key)
bstInsert(root->left, data);
else if (data > root->key)
bstInsert(root->right, data);
}
int main()
{
ifstream in1("InTest1.txt"); // InTest1.txt:1 2 4 3 5 52 2 4
BST_node* root = NULL;
int suppVar;
while (!in1.eof())
{
in1 >> suppVar;
bstInsert(rootEng, suppVar);
}
BST_node* tmp = bstSearch(rootEng, 2);
if (tmp == NULL)
cout << "There is no element with given key";
else
cout << "key = " << tmp->key;
}
OUT: key = 2
And also i put the code of string key version of my tree below:
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
using namespace std;
typedef struct BST_str
{
string key;
BST_str* right;
BST_str* left;
BST_str* engWordPtr; // pointer to node in translation tree (not used yet)
}BST_strNode;
BST_strNode* CreateNewStrNode(string data) // function that returns new node of my tree
{
BST_strNode* NewNode = new BST_strNode;
NewNode->key = data;
NewNode->right = NULL;
NewNode->left = NULL;
NewNode->engWordPtr = NULL;
return NewNode;
}
BST_strNode* bstStrSearch(BST_strNode* root, string data) // search function
{
if (root == NULL)
return NULL;
else if (strcmp(root->key.data(), data.data()) == 0)
return root;
else if (strcmp(root->key.data(), data.data()) < 0)
bstStrSearch(root->right, data);
else if (strcmp(root->key.data(), data.data()) > 0)
bstStrSearch(root->left, data);
}
void bstStrInsert(BST_strNode*& root, string data) // insert function
{
if (root == NULL)
root = CreateNewStrNode(data);
else if (strcmp(root->key.data(), data.data()) > 0)
bstStrInsert(root->left, data);
else if (strcmp(root->key.data(), data.data()) < 0)
bstStrInsert(root->right, data);
}
int main()
{
ifstream in1("InTest2.txt"); // InTest2.txt:O G X E OH D F I OA H OB OX
BST_strNode* rootEng = NULL;
string suppVar;
while (!in1.eof())
{
in1 >> suppVar;
bstStrInsert(rootEng, suppVar);
}
BST_strNode* tmp = bstStrSearch(rootEng, "OXcasdf");
if (tmp == NULL)
cout << "There is no element with given key";
else
cout << "key = " << tmp->key;
}
OUT: key =
And program crashes, it doesnt matter if i want to search for string that is already there or not, always the same result, probably its returning some garbage instead of node or NULL but i don't really know why it's working on integer tree, but on string tree doesn't. It also generates 3 warnings:
Warning C26495 Variable 'BST_str::engWordPtr' is uninitialized. Always initialize a member variable (type.6).
Warning C26495 Variable 'BST_str::left' is uninitialized. Always initialize a member variable (type.6).
Warning C26495 Variable 'BST_str::right' is uninitialized. Always initialize a member variable (type.6).
And also an exception while debugging:
Exception thrown: read access violation. this was 0x45.
Thanks for the help in advance.
The recursive function bstSearch is incorrect because it does not return a node in each its path of execution
BST_node* bstSearch(BST_node* root, int data) // search function
{
if (root == NULL)
return NULL;
else if (root->key == data)
return root;
else if (root->key < data)
bstSearch(root->right, data);
else
bstSearch(root->left, data);
}
The last if else statements should look like
else if (root->key < data)
return bstSearch(root->right, data);
else
return bstSearch(root->left, data);
Also for the function designed for strings there is no need to use the C function strcmp. The function could be defined the following way
BST_strNode* bstStrSearch( BST_strNode* root, const string &data) // search function
{
if (root == NULL)
return NULL;
else if ( root->key == data )
return root;
else if ( root->key < data )
return bstStrSearch(root->right, data);
else
return bstStrSearch(root->left, data);
}
Pay attention to that the condition of the while loop
while (!in1.eof())
{
in1 >> suppVar;
bstStrInsert(rootEng, suppVar);
}
is incorrect. The eof state can occur after this statement
in1 >> suppVar;
Instead you should write
while ( in1 >> suppVar)
{
bstStrInsert(rootEng, suppVar);
}
Note when compiled, the compiler should print a warning along the lines of:
warning: control may reach end of non-void function
in reference to bstStrInsert. Indeed, looking at the function definition, the two recursive branches don't return a value.
To prevent the warning (and this sort of error in general), you can use a local variable to hold the result, and have a single return.
Additionally, the functions should be rewritten as member function of the BST node class. You can also use templates (and template specializations) rather than creating separate, unrelated BST classes for each key type. With scohe001's protip, the template functions will work with any key type that implements standard comparison operators (so you don't have to write a specialization for std::string).
template<typename K> BST_Node<K>* BST_Node<K>::search(BST_Node<K>* node, const K& data) {
BST_Node<K>* result = NULL;
if (node) {
if (node->key == data)
result = node;
else if (node->key < data)
result = search(node->right, data);
else // if (node->key > data)
result = search(node->left, data);
}
return result;
}
Since the last branch covers all remaining cases, the if (node->key > data) test is unnecessary.
The above BST_Node<K>::search has an extra BST_Node<K>* argument that isn't strictly necessary. An alternative is to call search on each node, which means moving the pointer test to immediately before each recursive call (and operating on this, rather than the extra node argument).
template<typename K> BST_Node<K>* BST_Node<K>::search(const K& data) {
BST_Node<K>* result = NULL;
if (key == data)
result = this;
else if (key < data) {
if (right) {
result = right->search(data);
}
} else if (left) // (key > data)
result = left->search(data);
return result;
}
In general, an interactive debugger is your most powerful tool for troubleshooting crashes and unexpected behavior. Find and learn to use whatever debugger your development suite provides.
Additional
As noted in C++ references, passing string::data to C string functions can result in undefined behavior, as it's not guaranteed to be null terminated. string::c_str should be used for that purpose, but (in general) C string functions should only be used when interacting with C code (such as libraries).
When printing a message, be sure to include a newline. This can be done with a newline in the string, but better is to output std::endl, which will also flush the output buffer (if output is buffered, which it probably is).
Importing all of std into the current namespace is fine for one-offs, sample and practice code, but shouldn't be done in production. Importing specific symbols (such as std::cin, std::cout and std::endl) is fine and unlikely to cause collisions.
I am implementing a tree node function. But I am stuck at delete node.
It keeps giving this error. I have tried this with TreeNode* function and it totally works but this one keeps giving an error when I tried to change it to a void function.
I am trying to change this into a void function.
void Tree::deleteFrom(TreeNode* startintPoint, int value)
//from example in class, deleting a node
if (startintPoint == nullptr)
{
return;
}
else if (startintPoint->left != nullptr && value < startintPoint->value)
{
startintPoint->left = deleteFrom(startintPoint->left, value);
}
else if (startintPoint->right != nullptr && value > startintPoint->value)
{
startintPoint->right = deleteFrom(startintPoint->right, value);
}
else
{
if (startintPoint->left == nullptr && startintPoint->right == nullptr)
{
delete startintPoint;
startintPoint = nullptr;
}
else if (startintPoint->left == nullptr)
{
TreeNode* temp = startintPoint;
startintPoint = startintPoint->right;
delete temp;
}
else if (startintPoint->right == nullptr)
{
TreeNode* temp = startintPoint;
startintPoint = startintPoint->left;
delete temp;
}
else
{
TreeNode* temp = findMinValue(startintPoint->right);
startintPoint->value = temp->value;
startintPoint->right = deleteFrom(startintPoint->right, temp->value);
}
}
return startintPoint;
}
Since the return type of the function is void, the compiler does not like the lines
startintPoint->left = deleteFrom(startintPoint->left, value);
and
startintPoint->right = deleteFrom(startintPoint->right, value);
The RHS of those statements is of type void while the LHS is of type TreeNode*.
You need to change the return type of the function to TreeNode*. That will allow you to use lines.
And then make sure to return the right pointer from the function, which you seem to be already doing.
You assign like startintPoint->left = deleteFrom(...), but deleteFrom's return value is of type void, i.e. void deleteFrom(...). So it won't return any value that could be assigned.
You could change void Tree::deleteFrom(TreeNode* startintPoint, int value) into TreeNode* Tree::deleteFrom(TreeNode* startintPoint, int value).
If you want to leave deleteFrom as it is, you could introduce an additional (probably protected or private function) like TreeNode* Tree::deleteFromRecursive(TreeNode* startintPoint, int value) which call itself recursively and which is called once by deleteFrom.
I was doing last exercise from this list (its called graduation): http://www.cplusplus.com/forum/articles/12974/ but had one major problem. The code I wrote runs, but it will crash at so time (after deleting half bunnies), sometimes after program deletes half bunnies first time, sometimes after 10 such cycles, note that i havent implemented alot yet because i want to fix this bug, with your help of course. Also I know this is not code review, but some small tips about style and improving would be good too. So this is code i wrote so far:
Main.cpp:
include bunnyList.h
include windows.h
using namespace std;
int main(){
srand(time(NULL));
bunnyList Colony;
int turns = 0;
Colony.setUp();
while(Colony.getColonySize() > 0){
//New turn
Colony.increaseAgeAndKill();
Colony.breedBunnies();
std::cout << "Turn: "<< turns << ". Colony size: " << Colony.getColonySize() << std::endl;
//Get rid of these food eaters
if(Colony.getColonySize() > 1000){
std::cout << "500 bunnies died!" << std::endl;
Colony.killHalfBunnies();
}
Sleep(100);
turns++;;
}
}
bunnyList.h:
#ifndef BUNNYLIST_H
#define BUNNYLIST_H
#include <stdlib.h>
#include "node.h"
#include <time.h>
#include <iostream>
#include <string>
const int numOfNames = 4;
const int numOfColors = 4;
const int bunniesIni = 5;
const std::string colors[numOfColors] = {"Black", "White", "Brown", "Spotted"};
const std::string maleNames[numOfNames] = {"Joe", "Rafael", "Buby", "Messi"};
const std::string femaleNames[numOfNames] = {"Reichel", "Agnesa", "Mr Flufy", "Flower"};
class bunnyList{
private:
node *head;
int noOfBunnies;
node *current, *prev;
public:
bunnyList();
void newBunny(std::string);
void killHalfBunnies();
void increaseAgeAndKill();
void deleteNode();
void breedBunnies();
void setUp();
int getRandomNumber(int) const;
std::string getRandomColor();
std::string getRandomName(bool);
bool isMaleRandom();
int getColonySize() const;
};
#endif
bunnyList.cpp:
#include "bunnyList.h"
bunnyList::bunnyList(){
noOfBunnies = 0;
}
void bunnyList::setUp(){
std::string temp = "";
head = NULL;
for(int i = 0; i <= bunniesIni; i++){
newBunny(temp);
}
}
void bunnyList::killHalfBunnies(){
prev = head;
current = head;
while(noOfBunnies > 500){
if(getRandomNumber(2) == 1){
deleteNode();
continue;
} else if(current == NULL){
current = head;
prev = head;
} else {
prev = current;
current = current->next;
continue;
}
}
}
void bunnyList::newBunny(std::string color){
node *bunny = new node();
node *temp = head;
if(color == ""){
bunny->color = getRandomColor();
} else {
bunny->color = color;
}
bunny->isMale = isMaleRandom();
bunny->name = getRandomName(bunny->isMale);
bunny->age = 0;
bunny->next = NULL;
bunny->isBreedable = 0;
if(head == NULL){
head = bunny;
return;
}
while(temp->next != NULL){
temp = temp->next;
}
temp->next = bunny;
noOfBunnies++;
}
void bunnyList::increaseAgeAndKill(){
current = head;
prev = head;
while(current != NULL){
current->age++;
//Check if bunny can breed
if(current->age > 2){
current->isBreedable = 1;
}
//Check if its time to die :/
if(current->age > 10){
deleteNode();
}
prev = current;
current = current->next;
}
current = head;
prev = head;
}
void bunnyList::breedBunnies(){
node *temp = head;
bool oneMale = 0;
int femaleCount = 0;
//Check if there is at least one breedable male
while(temp!=NULL){
if(temp->isMale && temp->isBreedable){
oneMale = 1;
break;
}
temp = temp->next;
}
//For every female bunny over 2 years old a new bunny is born
temp = head;
if(oneMale){
while(temp != NULL){
if(temp->isMale == 0 && temp->isBreedable){
newBunny(temp->color);
}
temp = temp->next;
}
}
}
void bunnyList::deleteNode(){
if(current==head){
head = current->next;
prev = head;
delete current;
current = head;
noOfBunnies--;
} else if(current->next==NULL){
delete current;
prev->next = NULL;
prev = head;
current = head;
noOfBunnies--;
} else {
prev->next = current->next;
current->next = NULL;
delete current;
current = prev->next;
noOfBunnies--;
}
}
std::string bunnyList::getRandomName(bool isMale){
int r = getRandomNumber(numOfNames - 1);
if(isMale)
return maleNames[r];
return femaleNames[r];
}
std::string bunnyList::getRandomColor(){
int r = getRandomNumber(numOfColors - 1);
return colors[r];
}
bool bunnyList::isMaleRandom(){
if(getRandomNumber(2) == 1) {return true;}
return false;
}
int bunnyList::getRandomNumber(int limit) const{
return rand() % limit + 1;
}
int bunnyList::getColonySize() const{
return noOfBunnies;
}
node.h:
#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
#include <string>
class node {
friend class bunnyList;
private:
std::string name;
int age;
std::string color;
bool isMale;
node *next;
bool isBreedable;
public:
};
#endif // NODE_H_INCLUDED
Thank you for your help.
Since you asked for the review...
NEVER write using namespace std. Never. Just this morning there was a problem asked on SO where the reason for the issue at hand was that notorious line. I wonder who and why suggested that this is a good approach - there should be a book somewhere with this. If I had my way, it's author would be condemned to eternal manual removal of this line from every file.
Even without reading a line from the code, just by explanations alone, I know that the problem is most likely (100% likely, as in) to be related to memory management. You are freeing the memory which was not allocated properly, you are freeing the same memory twice or you are freeing something which was not allocated at all or you are accessing the memory after it was freed. Look at your deletes and check them.
On the style. Your code basically is an implementation of the business logic-aware list. Generally, this is not a good practice. It is much better to implement a generic list, supporting addition, deletion and other generic list operations, and than implement your business logic on top of this generic list.
Do not use current in your list. Instead, pass a node to be deleted in your delete function.
Lastly, run your program in the debugger and look into the variables you are deleting.
EDIT
Answering questions in commments.
Here is what I meant by business logic separation. There is a generic data structure, called list. It can be a list of anything, bunnies or space rockets, doesn't matter - but it still supports the basic list operations. Obviously, the two most important are insert and delete, but it is not the only operations for generic list. You can read wikipedia on list (data structure) for general ideas and look into std::list as in implementation. Now, you have your specific use case for list, a list of bunnies. For that specific use case you will add functionality on top of generic list. To clarify further, deleting an item from the list is something generic list supports. But 'killing a rabit' when the poor creature ages 10 years is something of the business logic. It contains iterating over list of rabbits (provided by generic list), checking age and making a decision to eliminate the creature (business-logic level) and than deleting the element (generic list). If this code were to be written using std::list, it would like approximately following:
std::list<Bunny> bunnies;
for (auto bunny = bunnies.cbegin(), end = bunnies.cend(); bunny != end; ++bunny) {
if (bunny->age() > 10)
bunny = bunnies.erase(bunny);
}
I got a crash too. It crashed in deleteNode, trying to reference current->next when current was NULL.
This was called from bunnyList::killHalfBunnies, in this code, which is the problem I find:
if (getRandomNumber(2) == 1){
deleteNode();
continue;
}
else if (current == NULL){
current = head;
prev = head;
}
The problem is you call deleteNode, which assumes that current is not NULL, before checking that current is in fact not NULL. I rearranged the if's as shown here, and I'm no longer getting a crash:
if (current == NULL)
{
current = head;
prev = head;
}
else if (getRandomNumber(2) == 1)
{
deleteNode();
continue;
}
It would also be wise to put a check inside deleteNode, so that if it is called when current is NULL, it can handle it. Possibly by throwing an exception or otherwise warning you.
Since you also asked about style: comments in deleteNode (and elsewhere) would make it all clearer!
I assume this is a class assignment, and that's why you're not using std::list.
I'm trying to find a way of deleting a linked list without recursion, because a stack overflow isn't really something nice.
I have a struct as follows:
typedef struct _my_Item
{
_my_Item(const std::string& name)
{
m_name = name;
}
~my_Item()
{
delete next; // this recursively deletes the "tail" of the list
next = NULL;
}
struct _my_Item *next;
std::string m_name;
// ... More members here...
}
In some piece of code (not relevant here) I'm constructing a list from a data file using the above structure. I keep the pointer to the head of the list in a variable and can work with it. All fine.
When I finally call the destructor on the head of the list, the destructor gets called and the delete next; causes a recursion to delete the "tail" of the list (which is the entire list without the first element). Now since the list is quite long, I see a stack overflow sometimes.
Is there a nice way to get around this problem?
~my_Item()
{
while (next)
{
_my_Item* item = next;
next = item->next;
item->next = NULL; // this prevents the recursion
delete item;
}
}
Create a class representing the list itself that will encapsulate nodes deletion in its destructor via a for/while loop. Doing it the way you do leaves the possibility to delete part of the list and leave dangling pointer.
One suggestion would be to remove the delete code from the destructor and use a pointer to delete the list.
struct _my_Item * nodeToDelete = NULL;
while(firstNode != NULL)
{
nodeToDelete = firstNode;
firstNode = firstNode->next;
delete nodeToDelete;
}
// I wrote this java code to delete a node from BST
// I only used one recursion call to remove successor
public Boolean delete(int data){
if(isEmpty() || !search(data))
return false;
return delete(null,root,data);
}
public Boolean delete(Node parent,Node temp,int data) {
while(true){
if(data == temp.getData()) {
break;
} else if(data < temp.getData()) {
parent = temp;
temp = temp.getLeft();
} else {
parent = temp;
temp = temp.getRight();
}
}
if(parent == null && (temp.getLeft() == null || temp.getRight() == null)){
if(temp.getLeft() == null)
root = temp.getRight();
else
root = temp.getLeft();
} else if(temp.getLeft() == null || temp.getRight() == null) {
if (parent.getLeft() == temp) {
if (temp.getLeft() == null)
parent.setLeft(temp.getRight());
else
parent.setLeft(temp.getLeft());
} else if (parent.getRight() == temp) {
if (temp.getLeft() == null)
parent.setRight(temp.getRight());
else
parent.setRight(temp.getLeft());
}
}else{
int min = findMin(temp.getRight());
temp.setData(min);
delete(temp,temp.getRight(),min);
}
return true;
}
I want to create tree in C++.
I could compile the code without errors or warnings, but i don't get an output.
I think error is in inorder fn, but don't know how to remove this.
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
struct tree
{
int data;
struct tree * left;
struct tree * right;
};
typedef struct tree * TREE;
TREE maketree(int x)
{
TREE tree = (TREE)malloc(sizeof(tree));
if(tree == NULL)
{
return NULL;
}
tree->left = tree->right = NULL;
tree->data = x;
return tree;
}
void setleft(TREE tree,int x)
{
if(tree == NULL || tree->left != NULL)
{
cout<<"\t Error !! Inserting New Node At Left Side !\n";
}
else
{
tree->left = maketree(x);
}
}
void setright(TREE tree,int x)
{
if(tree == NULL || tree->right != NULL)
{
cout<<"\t Error !! Inserting New Node At Right Side !\n";
}
else
{
tree->right = maketree(x);
}
}
void inorder(TREE root)
{
if(root != NULL)
{
TREE left=root->left;
TREE right=root->right;
inorder(left);
cout<<root->data;
inorder(right);
}
}
void main()
{
clrscr();
TREE root = NULL,child,parent;
int i,j = 1;
cout<<"Root Of Binary Search Tree :- ";
cin>>i;
root = maketree(i);
cout<<"\n\n";
while(i)
{
cout<<j<<" Node Value:- ";
cin>>i;
if(i < 0)
{
break;
}
parent = child = root;
while((i != parent->data) && (child != NULL))
{
parent = child;
if(i < parent->data)
{
child = parent->left;
}
else
{
child = parent->right;
}
}
if(i == parent->data)
{
cout<<"\t Value "<<i<<" Already Present In BST !!\n";
}
else if(i < parent->data)
{
setleft(parent,i);
}
else
{
setright(parent,i);
}
j++;
}
inorder(root);
getch();
}
If you want to write in C++ then write in C++. Use constructors and destructors and class methods. Possibly make your data members private. And use new rather than malloc and your destructors will probably want to delete (the child nodes of the tree).
What you have written is in C other than you've incorporated the worst feature of C++, iostream, and that in its old deprecated non-standard version.
This looks like some school exercise.
I also can't see anywhere where you free the data you have allocated with malloc.
Your sorting logic should be in a tree-based function, not main.
Your "error" may be the lack of whitespace in the output, but I don't know.
It's legal but not good practice to use tree as both a data-type (it's a struct, which in C++ does not need qualifying with struct) and a variable (for which it is often being used).
Ok, now a bit of code, mostly based on yours.
class tree
{
tree * left;
tree * right;
int value;
public:
explicit tree( int v );
~tree();
bool insert( int v );
void print( std::ostream& ) const;
private:
tree( const tree& );
tree& operator=( const tree& );
};
tree::tree( int v ) :
left( NULL ),
right( NULL ),
value( v )
{
}
tree::~tree()
{
delete right;
delete left;
}
bool tree::insert( int v )
{
// inserts v in the correct place in the tree, returns true
// if it inserted or false if it already exists
// I want you to fill in the detail for this function
}
void tree::print( std::ostream& os ) const
{
// prints the tree
if( left )
{
left->print( os );
}
os << value << '\n';
if( right )
{
right->print( os );
}
}
There, I have left one function for you to implement. You do not need to implement the private copy constructor or assignment operator.
Also implement main(). Note that there is no need to implement the tree in main on the heap (with new). Implement it on the stack.
main() will read in the numbers, insert them in to the tree calling its insert() method and then at the end print the tree, passing std::cout as a parameter.
You need to #include <iostream> (not iostream.h) and it will work.