Searching for a node in a tree structure - c++

I need help finding and returning a "node" in a general tree structure. Each node can have more than 2 children so it's not a binary tree. I've been given the following code, this Element object has a list to contain its children, I create one element node pointer in main and using that I have to add and search for children. This is for a school project but I'm not looking for answers (an answer wouldn't hurt). Any advice on how to go about this problem would be much appreciated, thanks!
#pragma once
#include <iostream>
#include <list>
#include <sstream>
using namespace std;
class Element
{
private:
list<Element*> children;
char* _tag;
int _value;
// private methods
public:
// default constructor
Element();
// non-default constructors
Element( char* name); // value is set to -99 if not given
Element(char* name, char* value);
// destructor, must recursively destruct its children
// and release the memory allocated for _tag
~Element();
// ostream operator ( pre-order traversal)
friend ostream& operator << (ostream& out, const Element& E);
void display_xml(); // print out the tree in xml-- format
void addChild( Element* child); // add a child
// Find the first element such that _tag == tag
// returns “this” pointer of this element
Element* findTag( char* tag);
char* getName();
int getValue();
void setName(char* name);
void setValue( int value);
int height(); //b return the height
int size(); // return the size
// other methods
};
this is my best attempt at a solution, it has obvious problems but I'm new to all of this and some explanation on a proper solution, or some sample code would be very helpful!
Element* Element::findTag(char* tag)
{
list<Element*> temp = children;
int s = temp.size();
if(getName() == tag)
{
return this;
}
else
{
for(int i = 0; i < s; i++)
{
findTag((*temp.front()).getName());
temp.pop_front();
}
}
}

I will give you a pseudo-code for searching for a node that has a value val in a tree rooted at root:
find(Node root, val)
if(root.value == val) return root //-- if the recursion found the node we are searching for
else
for every child x of root //-- re-cursing on the children of root
if(find(x, val) != null) return x //-- if one of the calls found the node we are searching for
return null //-- if we did not find the node we want in the sub-tree rooted at root

Related

searchable linked list in c++

everyone
I am working on an RPG game as a class project.
A linked listis used for the inventory.
I try to add a search function since I want the user to be able to sell inventory.
The ideal is that searchItem(string name) takes the given item name and goes through the list finding the name-matched item, then return address of the item. However, when the function called, the IDE throws a EXC_BAD_ACCESS(code=1, adress0x44) error.
I guess it doesn't return the right address but with my current ability, I can't figure out the solution.
Any help will be really appreciated.
Inventory.hpp
#include <stdio.h>
#include <list>
#include <iostream>
#include "Item.hpp"
using namespace std;
class Inventory{
private:
struct Inven{
Item item;
struct Inven *next = nullptr;
};
Inven *head;
public:
Inventory();
~Inventory();
void appandItem(Item obj);
void insertItem(Item obj);
void deleteItem(string name, int qt);
void displayInventory();
Item* searchItem(string name);
};
Inventory.cpp
I only posted searchItem function because others work fine
Item* Inventory::searchItem(string name){
// to go through the inventory
Inven *itemPtr = nullptr;
// to point to the previous item
Inven * previousItem = nullptr;
// if the invnetory is empty, nothing happands
if(!head)
return nullptr;
// determine if the first item is the one.
if(head->item.getName() == name){
// if so, return the address of item
return &itemPtr->item;
}else{
// Initialize itemPtr to head of inventory
itemPtr = head;
// skip all items whose name is not match
while (itemPtr != nullptr && itemPtr->item.getName() != name){
previousItem = itemPtr;
itemPtr = itemPtr->next;
}
// return the address found
if (itemPtr){
return &itemPtr->item;
}
}
return nullptr;
}
here is the code where searchItem is called, can not access to getSellValue() which is defined in Item class
#include "Shop.hpp"
// sell inventory for gold
int Shop::sell(Inventory inventory, string itemName, int qt){
this->goldEarned = inventory.searchItem(itemName)->getSellValue() * qt;
inventory.deleteItem(itemName, qt);
return this->goldEarned;
}
Let me know if more information is needed.

Creating instances for a linked list class in C++

I am currently learning C++ linked list and I hit this piece of code from the textbook.I have trouble understanding this:
const string& e
I am trying to write some instances for this class in my main function to see how things works but don't know how.
For example, I want to add 3, 5, 7 to the list and add 1 to the front of the list, than delete 7 from the list.
#include <cstdlib>
#include <iostream>
#include <string>
using std::string;
using namespace std;
class StringNode { // a node in a list of strings
private:
string elem; // element value
StringNode* next; // next item in the list
friend class StringLinkedList; // provide StringLinkedList
// access
};
class StringLinkedList { // a linked list of strings
public:
StringLinkedList(); // empty list constructor
~StringLinkedList(); // destructor
bool empty() const; // is list empty?
const string& front() const; // get front element
void addFront(const string& e); // add to front of list
void removeFront(); // remove front item list
private:
StringNode* head; // pointer to the head of list
};
StringLinkedList::StringLinkedList() // constructor
: head(NULL) { }
StringLinkedList::~StringLinkedList() // destructor
{ while (!empty()) removeFront(); }
bool StringLinkedList::empty() const // is list empty?
{ return head == NULL; }
const string& StringLinkedList::front() const // get front element
{ return head->elem; }
void StringLinkedList::addFront(const string& e) { // add to front of list
StringNode* v = new StringNode; // create new node
v->elem = e; // store data
v->next = head; // head now follows v
head = v; // v is now the head
}
void StringLinkedList::removeFront() { // remove front item
StringNode* old = head; // save current head
head = old->next; // skip over old head
delete old; // delete the old head
}
I tried to look for a duplicate which explains how C++ uses call-by-value.
In C++ a function parameter of type T will make a copy of the object before the function is called.
int myFunction( int value )
{
value = value + 1;
}
int main( int argc, char * argv[] )
{
int elem = 6;
myFunction( elem );
printf( "%d\n", elem ); // elem = 6;
}
In the above example a copy is made of the int value, which is sent to myFunction, and the copy is incremented.
This may not be what is wanted, and we can change the result to 7, by modifying myFunction to take a reference to the value. This is done by using the '&' to describe a reference value.
int myFunction( int & value )
{
value = value + 1;
}
int main( int argc, char * argv[] )
{
int elem = 6;
myFunction( elem );
printf( "%d\n", elem ); // elem = 7;
}
In the above case, no copy is made, and elem gets updated.
There are 2 main reasons you pass references to a function
To allow the value (or object) to be updated.
To avoid the cost of copying the value.
In your quoted example the second case is why the const string & is used (reference to string object). std::string, has costs to construct and destroy, so by sending a reference to avoid this, is more efficient.
To compliment this usage, the reference, is usually made const to convince the compiler that the value should not be changed.

Binary Tree (insert and search within radius)

I am writing a binary tree search program but I'm not sure how to add nodes and search through them. The nodes come from a .txt file that is being read with a different file so just assume that already works.
The text file looks like:
Name Location
Old Building 31.2222
New Building 21.2111
Like I said, the program already reads in the file so that's not an issue. However, I have to insert the name and location into the nodes of the binary tree. Then I have to search everything within a range which is where the plus minus comes from.
Side note: my copy constructor may be incorrect as well though it complies properly.
Thanks for the help!
#ifndef BINTREE_HPP
#define BINTREE_HPP
#include <utility>
#include <string>
#include <vector>
class bintree {
// A binary search tree for locations in Lineland.
// Notes:
// - Assume a flat, one-dimensional world with locations from -180 to 180.
// - All locations and distances are measured in the same units (degrees).
public:
// Default constructor
bintree() {
this->root = NULL;
}
// Copy constructor
bintree(const bintree &t) {
this -> root = NULL;
*this = t;
}
// Destructor
~bintree() {
}
// Copy assignment is implemented using the copy-swap idiom
friend void swap(bintree &t1, bintree &t2) {
using std::swap;
// Swap all data members here, e.g.,
// swap(t1.foo, t2.foo);
// Pointers should be swapped -- but not the things they point to.
}
bintree &operator= (bintree other) {
// You don't need to modify this function.
swap(*this, other);
return *this;
}
void insert(const std::string& name, double p) {
// insert node with name and location (p)
}
void within_radius(double p, double r, std::vector<std::string> &result) const {
// Search for elements within the range `p` plus or minus `r`.
// Clears `result` and puts the elements in `result`.
// Postcondition: `result` contains all (and only) elements of the
// tree, in any order, that lie within the range `p` plus or minus
// `r`.
}
private:
struct node
{
node *left;
node *right;
};
node* root;
};
#endif
First, your nodes need to hold the data:
struct node
{
node *left;
node *right;
std::string name; // This is the key for your reasearch
double p; // followed by other data
};
Then you can think to browsing through your tree to insert a new node.
In this example, I assume that you can insert several nodes with the same name.
void insert(const std::string& name, double p) {
node *n = new node; // create a new node
n->name=name; n->p=p; // intialise the data payload
n->left=n->right=nullptr; // and make it a leaf.
if (root==nullptr) // if tree is empty,
root = n; // add the new node.
else { // else find where to insert it
node* t=root;
while (true) {
if (t->name > n->name) { // go to left
if (t->left==nullptr) {
t->left = n;
break;
}
else t=t->left;
}
else if (t->name == n->name) { // insert between current and next
n->right = t->right;
t->right = n;
break;
}
else { // go to right
if (t->right==nullptr) {
t->right = n;
break;
}
else t=t->right;
}
}
}
}
Here a live demo.
Note that I have only answered your insertion question, you still have to do a lot on your own (operator= and copy constructor need review, a destructor needs to be created, etc...)

Eclipse complains about recursive function call

A simple binary search tree class declaration:
#include <vector>
#include <stdio.h>
// Provides various structures utilized by search algorithms.
// Represents an generalized node with integer value and a set of children.
class Node {
protected:
std::vector<Node*> children;
int value;
public:
//Creates a new instance of a Node with a default value=-1.
Node(){value = -1;}
//Creates a new instance of a Node with a specified value.
explicit Node(int value){this->value = value;}
virtual ~Node(){delete children;}
//Adds new Node with specified value to the list of child nodes. Multiple
//children with the same value are allowed.
//Returns added node.
virtual Node* Insert(int value);
//Removes first occurrence of a Node with specified value among children.
virtual void Remove(int value);
};
// Represents a binary search tree node with at most two children.
class BTNode: public Node {
public:
//Creates a new instance of a BTNode with a default value=-1.
BTNode():Node(){}
//Creates a new instance of a BTNode with a specified value.
explicit BTNode(int value):Node(value){}
//Adds new BTNode with specified value to the list of child nodes in an
//ordered manner, that is right child value is >= value of this node and
//left child value < value of this node.
virtual BTNode* Insert(int value);
//Removes first occurrence of a Node with specified value from the tree.
virtual void Remove(int value);
//Returns a node with specified value.
virtual BTNode* Search(int value);
};
And eclipse complains about it's definition:
BTNode* BTNode::Search(int value){
if (this->value == value) return *this;
//Determines whether value is in left(0) or right(1) child.
int child = this->value > value ? 0 : 1;
if (children[child] != NULL)
return children[child]->Search(value);
return NULL;
}
exactly where the call children[child]->Search(value) takes place with a message "method Search could not be resolved". Build runs just fine (no compilation errors whatsoever). What's the problem with that?
P.S.:Haven't tried running the code,yet. Working on it.
Search is part of the BTNode interface but it is not part of Nodes interface, children is a vector of Node* so it is not valid to call Search on a Node *. If it makes sense for Node to have a Search method then adding it to Node would fix that issue. If not then you need to rethink your design and that is probably beyond the scope of this question.
There are also a few other issues. You have:
virtual ~Node(){delete children;}
but children is not a pointer it is a std::vector<Node*>. You need to iterate over the vector and call delete each element. In Search you have this:
if (this->value == value) return *this;
but Search returns a BTNode* so it should be:
if (this->value == value) return this ;

Custom Queue Class C++

So I'm trying to create a Singly-linked-list Queue. I'm trying to write a function to add elements, and everything adds fine, but the problem is that its FILO instead of FIFO. I'm not sure how to handle my front and rear pointers.
#include <iostream>
#include <string>
using namespace std;
class Queue{
public:
Queue();
//~Queue();
void add(const string & item);
//string remove();
// unsigned items() const;
void show() const;
private:
struct Node{
string data;
Node *next;
};
Node *rear;
Node *front;
unsigned elements;
};
Queue::Queue():elements(0),rear(NULL),front(NULL){}
//Queue::~Queue(){
//}
void Queue::add(const string & item){
Node *t=new Node;
t->data=item;
t->next=rear;
if(front==NULL)
front=t;
rear=t;
elements++;
}
void Queue::show() const{
Node *p=rear;
for(; p->next!=rear; p=p->next){
cout<<" "<<p->data;
}
cout<<"\n";
}
int main(){
Queue obj;
obj.add("I");
obj.add("Am");
obj.add("Super");
obj.add("Cool");
obj.show();
}
currently it is neither FIFO nor FILO bu JINO (just in, never out).
what you do is to insert on the rear end. and your show does iterate from rear to front, because thats the only linked direction.
for an effective FIFO you would need a remove from the front end of your queue. you will notice, that you can find the front element, but you have no easy way to find the second element that is needed to set the front pointer. this is the drawback of your single linked design, you have to iterate from the rear to the front to find the element pointing to front.
with a single linked list you can do a FILO (actually more likely named LIFO or stack)
for a FIFO a double linked list would be the better design.
if you want to stick to a single linked list you could do some recursion. you eliminate the front pointer cause it is useless.
void Queue::show_one(Node *p) const{
if (p->next!=rear) { // i kept the test for p->next!=rear
// either fix add or test for p->next!=NULL
show_one(p->next);
}
cout<<" "<<p->data;
}
void Queue::show() const{
show_one(rear);
cout<<"\n";
}
likewise you could write a remove()
to achieve, FILO(like STACK?),
When push(add), append your new element at the end( you will deal with rear pointer)
When pop, get rid of the element that rear pointer points to.
In you code, your rear pointer points to one element after end, which is null. So push takes O(n), and also pop cost O(n). Its not efficient. So considering double linked list may be better choice for easy implementation.
I figured out how to reverse the entire thing so it works properly now. Is it efficient? It took 1.06ms to run main.
#include <iostream>
#include <string>
using namespace std;
bool die(const string &msg);
class Queue{
public:
Queue();
~Queue();
void add(const string & item);
string remove();
unsigned items() const;
void show() const;
private:
struct Node{
string data;
Node *next;
};
Node *rear;
Node *front;
unsigned elements;
};
Queue::Queue():elements(0),rear(NULL),front(NULL){}
Queue::~Queue(){
unsigned el=items();
for(unsigned i=0; i<el; i++)
remove();
}
unsigned Queue::items()const{
return elements;
}
string Queue::remove(){
if(front==NULL) die("underflow");
Node *t=front;
string data=t->data;
front=t->next;
delete t;
elements--;
return data;
}
void Queue::add(const string &item){
Node *t=new Node;
t->data=item;
t->next=NULL;
if(front==NULL)
front=t;
else{
Node *t2=rear;
t2->next=t;
}
rear=t;
elements++;
}
void Queue::show() const{
Node *t=front;
for(unsigned i=0; i<items(); i++, t=t->next)
cout<<t->data<<'\n';
}
bool die(const string &msg){
cout<<"Error: "<<msg;
exit(EXIT_FAILURE);
}
int main(){
Queue obj;
obj.show();
obj.add("poo");
obj.add("cra");
obj.add("bil");
obj.add("shi");
obj.show();
cout<<obj.remove()<<"\n";
cout<<obj.remove()<<"\n";
cout<<obj.remove()<<"\n";
cout<<obj.remove()<<"\n";
}