I'm programming a binary tree class template. When I add a new node I check if the new one is less or greater than current.
I overloaded < and > operator in the class type (Object) and works properly but the template doesn't call the overloaded operator, instead uses the generated by the compiler.
object.cc - Comparison between objects works outside the template
bool Object::operator<(const Object& par_other) const
{
printf("\n <");
return id_ < par_other.id_; //assume that you compare the record based on a
}
EDIT 1: Added some requested code. Thx for the help :)
struct Node {
T* value;
Node* left;
Node* right;
};
template <class T>
void BinaryTree<T>::add(T* par_T, Node* par_node) {
if (par_node == nullptr) {
par_node->left = nullptr;
par_node->value = par_T;
par_node->right = nullptr;
} else {
if (par_node->value == nullptr) {
par_node->value = par_T;
} else if (par_node->value > par_T) {
if (!par_node->right) {
par_node->right = createNode();
}
add(par_T, par_node->right);
} else if (par_node->value < par_T) {
if (!par_node->left) {
par_node->left = createNode();
}
add(par_T, par_node->left);
}
}
Why does a node have a T* instead of a T?
If you have a good reason to do that, then compare with:
*par_T < *(par_node->value)
and
*(par_node->value) < *par_T
Notice the use of * and notice I switched the sides rather than misuse >
If you didn't have a good reason to have a node contain a T* then get rid of the *s in this code (and correspondingly elsewhere) but still remember not to use >, ==, != etc. They all can be inferred by results of < ( a is "equal to" b when both a<b and b<a are false)
You also need to fix more things than you asked about. You seem generally confused about the nature of pointers. An extreme example from your code:
if (par_node == nullptr) {
par_node->left = nullptr;
par_node->value = par_T;
par_node->right = nullptr;
}
Think about what that code is doing!
Related
I'm trying to implement a class of Circular List with a nested class of iterator and I wrote like this:
template <class T>
class CircularList {
struct Item {
T data;
Item* next;
};
Item* head;
int size;
public:
CircularList() {
head = new Item();
head->next = head;
}
int sizeList() { return size; }
void push(T data) {
Item* i = new Item();
i->data = data;
i->next = head->next;
head->next = i;
size++;
}
class CircularListIterator {
Item* p;
CircularListIterator() {
p = head->next;
}
bool hasNext() {
if(p->next != head) {
return true;
}
return false;
}
T next() {
T data_temp = p->data;
p = p->next;
return data_temp;
}
};
CircularListIterator* iterator() {
return new CircularListIterator();
}
};
int main() {
CircularList<string>* letters = new CircularList<string>;
letters->push("d");
letters->push("c");
letters->push("b");
letters->push("a");
Iterator<string>* it= new Iterator<string>;
it = letters->iterator();
while (it->hasNext()) {
cout<< it->next() << "," << endl;
}
return 0;
}
But the Iterator is not working when I try to create an iterator in the main function, It said that it wasn't declared in the scope and has no member of it.
Assuming by "in the main class" you mean in the main function, the problem is quite straightforward: you're trying to construct a ::Iterator<string>, but there is no class in the global namespace (or anywhere else, in this code sample) called Iterator! You could try constructing a CircularList<string>::CircularListIterator - that's at least a class that exists - but it wouldn't work because the iterator needs to be associated with a CircularList object for it to be able to access member variables like head.
The correct thing to do here is to promote the iterator function - the one that returns a CircularListIterator* - out of the CircularListIterator class and into the CircularList class. Then, in your main function, you can call letters->iterator() and it'll return a CircularListIterator* for the letters object.
Now, CircularListIterator doesn't inherit from any other iterator classes - neither the (nonexistent-in-this-code Iterator you've typed it as, nor the C++ std::iterator or any of its variants) - so you can't assign it to it or probably even compile the code that references Iterator. To make CircularListIterator a subclass of std::iterator, you'll need to extend std::iterator<Category, T> with the appropriate category. See https://www.cplusplus.com/reference/iterator/iterator/ for more information on the std::iterator class template, including an example of implementing it.
I'm reading lines from a file and storing them into linked list.
void add(llist *list, somevalue) {
Node *newnode = (Node *) malloc(sizeof(Node));
newnode->value = somevalue;
newnode->next = list->head;
list->head = newnode;
}
and I call this function from an initialize function which opens the file and reads lines from the file.
void init() {
llist *list = (llist *) malloc(sizeof(llist));
//
//bunch of file i/o codes
//
while (read file until it returns NULL) {
add(list, line);
//if I try to print the values of the list here it works.
}
//Outside the loop, the head is back to NULL
}
And another problem that I realized is the values get concatenated every time I try to print the value. That is to say, the output would be:
First Loop: Tony
Second Loop: Peter
TonyPeter
Third Loop: Mir
PeterMir
TonyPeterMir
How do I fix it so the add function permanently adds the node to the linked list?
Why would the values be jumbled up like that?
----EDITED----
The list is a global variable, and here are some more snippets from the init function. This is the while loop with the problem:
//open file
//initialize & declare pointers
while (1) {
for (i = 0; i < max; i++) {
value[i] = '\0';
}
if (!(fgets(value,max,f))) {
//segfaults if I try to print out the list inside this block.
break;
}
add(list, value);
//the values are well separated in this statement
printf("id is %s\n", list->head->value);
//This print list works, but works weird as shown above.
print_list(list);
}
fclose(f);
//This print list doesn't work, the list is NULL
print_list(list);
And this is the print list function:
void print_users(llist *list) {
ListNode *e;
if (list->head == NULL) {
printf("NO USERS\r\n");
return;
}
e = list->head;
while (e != NULL) {
puts(e->id);
e = e->next;
}
}
So I don't have a good grasp at all on what you're exactly trying to do here, so we can only do but so much. You may consider posting a MCVE. However, I may be able to give you some pointers on building a linked list. I directly copied your add function into a linked list class that I just hurriedly built, and it worked fine, so there may be something else in your llist class that is causing the issue, or it could be something else in your code. The class and a brief description of the class are listed below.
basic node class
Note: I used templates, but you could just as easily remove the template statements and replace T with any type.
template<typename T>
class node {
private:
T data;
node* next;
public:
// The C++11 rule of 5
// Default Constructor
node(T value = T(), node* nxt = nullptr) : data(value), next(nxt) { }
// Copy Constructor
node(const node<T>& src) : data(src.data), next(src.next) { }
// Move Constructor
node(node<T>&& src) : data(src.data), next(src.next) {
src.data = T();
src.next = nullptr;
}
// Copy Assignment Operator
node<T>& operator=(const node<T>& src) {
this->data = src.data;
this->next = src.next;
return(*this);
}
// Move Assignment Operator
node<T>& operator=(node<T>&& src) {
this->data = src.data;
this->next = src.next;
src.data = T();
src.next = nullptr;
}
// Destructor
~node() {};
// Some functions to help with encapsulation
void set_next(node* nxt) {
this->next = nxt;
}
void set_data(T value) {
this->data = value;
}
node* get_next() {
return(this->next);
}
T& get_data() {
return(data);
}
};
linked list class body
Since you're using dynamic memory, you need to make sure you adhere to the rule of 3 or 5 depending on whether or not you're using C++11.
template<typename T>
class llist {
private:
node<T>* head;
public:
llist();
llist(const llist& src);
llist(llist&& src);
llist(~llist);
llist& operator=(const llist& src);
llist& operator=(llist&& src);
void push();
void insert();
};
default constructor
Nothing fancy here.
template<typename T>
llist<T>::llist() : head(nullptr) { }
copy constructor
Since you're using dynamic memory this is crucial
template<typename T>
llist<T>::llist(const llist& src) {
node<T>* tmp = src.head;
while(tmp) {
this->push(tmp->get_data());
}
}
move constructor
template<typename T>
llist<T>::llist(llist&& src) {
// delete current nodes
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
// steal the sources list
this->head = src.head;
src.head = nullptr;
}
destructor
template<typename T>
llist<T>::~llist() {
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
}
copy assignment operator
template<typename T>
llist& llist<T>::operator=(const llist<T>& src) {
node<T>* tmp = src.head;
while(tmp) {
this->push(tmp->get_data());
}
return(*this);
}
move assignment operator
template<typename T>
llist& llist<T>::operator=(llist<T>&& src) {
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
this->head = src.head;
src.head = nullptr;
return(*this);
}
push member
this is essentially opposite of your add member.
template<typename T>
void llist<T>push(T data) {
node<T>* new_node = new node<T>(data);
if(this->head) {
node<T>* tmp = this->head;
while(tmp->get_next()) {
tmp = tmp->get_next();
}
tmp->set_next(new_node);
} else {
this->head = new_node;
}
}
insert member
This is essentially your add member.
template<typename T>
void llist<T>insert(T data) {
node<T>* new_node = new node<T>(data, this->head);
this->head = new_node;
}
I don't know if this will help, and you probably already have and know most of this, but I hope it helps.
In this code, it would appear that you attempted to 'malloc' space for a "llist" user defined object.
void init() {
llist *list = (llist *) malloc(sizeof(llist));
//
//bunch of file i/o codes
//
while (read file until it returns NULL) {
add(list, line);
//if I try to print the values of the list here it works.
}
//Outside the loop, the head is back to NULL
}
First, you tagged this as C++. In C++, you simply must use new and delete. The C++ compiler does not associate "malloc" with the ctor / dtor of your user created object called "llist". And I assure you that you really do want to create these two methods, even when each are simple. Really.
On the other hand, the C++ compiler does provide New and Delete, and will automatically invoke the ctor and dtor when appropriate for both dynamic variables (in heap), and automatic variables (on stack). The compiler will not support this with malloc.
Second, your function init() does not return or otherwise deliver the value of the automatic variable you named "list" to any other scope. (Typically, a list lifetime exceeds the life of any function that uses or creates it.)
So your object "list" only exists within the scope of the function init(), within the lifetime of init(). Not very useful.
So the handle to the list of 'malloc'ed things is lost, no longer accessible to anything else. After init(), where did you plan for the listHead to reside?
Even if you used new (and delete) the code still does not deliver the listHead anywhere.
To further your program, you need perhaps 1 of 2 things:
1) a return (from the function) of the "list" handle (I've been calling it "listHead" as you intended, right?)
llist* init() {
llist *listHead = ...
return(listHead);
}
OR
2) a parameter reference which your init function changes. This places the list head outside of init().
void init( llist** listHead) {
llist *list = ...
*listHead = list;
}
You might look into, and take hints from std::list, which has 40+ methods, though you might only need 10. For the methods you plan to implement, you should strive to conform to and use similar names and parameters.
Perhaps you meant to use a class data attribute with the label list (it is quite difficult to imagine this from what you provided). In this case, you should distinguish data attributes names to help you remember what it is, and that it has a different scope. For instance, I would use m_listHead. The prefix m_ (or often, simply the one char prefix '_') simply indicates to the reader that this symbol is a data attribute of a class. This idea is a common c++ idiom, and not enforced by the compiler, but is often part of a coding-standard.
Good luck.
I'm trying to teach myself about classes in C++, and I'm running into a bit of a stumbling block, which I can't seem to clear up. I was hoping someone might be able to point me in the correct direction.
I decided to construct a small Tree class, which constructs a new BST. I want to be able to call certain methods on my object like so:
int main() {
Tree<int> tree1;
tree1.insert(5);
int treeMin = tree1.minValue();
int treeMax = tree1.maxValue();
tree1.printTree();
}
Right now, in order to call these functions, I am defining both public and private functions so that you don't call function in a redundant manner. for instance:
(what I'm trying to avoid)
int main() {
Tree<int> tree1;
tree1.insert(tree1, 5);
int treeMin = tree1.minValue(tree1);
int treeMax = tree1.maxValue(tree1);
tree1.printTree(tree1);
}
In order to do avoid having this redundancy, I am defining a public and private version of the same function. In this way, the public functions call their private counterparts.
template<class T>
class Tree {
private:
treeNode<T>* root;
treeNode<T>* newNode(T data);
void insert(treeNode<T>*& root, T data);
int minValue(treeNode<T>*& root);
int maxValue(treeNode<T>*& root);
void printTree(treeNode<T>*& root);
public:
Tree();
~Tree();
void insert(T data);
int minValue();
int maxValue();
void printTree();
};
And then, as an example:
template<class T>
int Tree<T>::minValue() { minValue(root); }
template<class T>
int Tree<T>::minValue(treeNode<T>*& root) {
if (root == NULL) { return 0; }
if (root->left == NULL) { return root->data; }
else { minValue(root->left); }
}
So, my question is:
If I'm writing my functions recursively, I understand that I need to declare a private function that accepts an argument, but is this considered a bad style? Is this sloppy?
Thanks for your help!
The private member functions in your code are only a needless complication. I would just move their code to the public member functions: less code, more clean code, less indirection so more directly grokable code, all nice. For some of them you might support reuse by making them free functions in a details namespace, but I think that would be premature generalization, expending effort on possible reuse that probably won't take place.
Example code at end of answer.
Re another design issue, declaring
int minValue();
int maxValue();
precludes calling these member functions on a const object. Instead do
int minValue() const;
int maxValue() const;
A third issue, it's generally a Really Bad Idea™ to do i/o in a non-i/o class. If you print the tree to standard output, how would you use the class in a GUI program? So, instead of
void printTree();
do e.g.
ostream& operator<<( ostream& stream ) const;
or e.g.
string toString() const;
A fourth issue, you need to take charge of copying – read up on the “rule of three” and the “rule of zero”.
The simplest way to do that is to replace
treeNode<T>* root;
with
unique_ptr< treeNode< T > > root;
where unique_ptr is std::unique_ptr.
Alternatively declare at least a copy constructor and a copy assignment operator, or inherit from a “non-copyable” class. To make the class effectively non-copyable, you can make these operators private or protected. To make it copyable, make them public and do the right thing in each (a good default implementation of the copy assignment operator is to express it in terms of copy construction via the copy-and-swap idiom, which means introducing a non-throwing swap function).
A fifth issue is that the implementation
template<class T>
int Tree<T>::minValue(treeNode<T>*& root) {
if (root == NULL) { return 0; }
if (root->left == NULL) { return root->data; }
else { minValue(root->left); }
}
strongly suggests that each node stores a value that's implicitly convertible to int. You don't provide the declaration of treeNode. But this looks like a design level bug, that the intent was for minValue to return a T, not an int – and ditto for maxValue.
A very small coding issue (not design level): in C++11 and later you should preferentially use nullptr, not NULL.
nullptr can be freely passed through argument forwarding functions, while NULL then suffers a decay to integral type, since NULL is just a zero-constant of integral type.
nullptr does not require that you include any header, while NULL is defined by a header, i.e. with nullptr you avoid a header dependency.
Finally, regarding
if (root == NULL) { return 0; }
for the minValue, this may of course be the intention, the design. But possibly you want to either signal failure or treat the call as a logic error.
To treat the call as an error, assert( root != nullptr ); and provide a means for the client code to check for empty tree.
To signal failure, either return an object with optional value (e.g. like boost::optional or Barton/Nackmann's original Fallible), or throw an exception (the std::runtime_error class is a good general default exception class choice).
It's also possible to combine the two approaches, to provide both, perhaps with names like minValue and minValueOrX.
More generally it's sometimes possible to reserve some special value as a "no such" indicator. E.g. std::numeric_limits<T>::min(). But this makes for brittle code, since such a value can easily occur naturally in the data, and since client code may easily fail to check for the special value.
Example, coded for C++11:
#include <assert.h>
#include <iostream> // std::cout, std::endl
#include <string> // std::string
namespace my {
using std::string;
template<class T>
class Tree
{
private:
struct Node
{
T value;
Node* p_left;
Node* p_right;
auto to_string() const -> string
{
using std::to_string;
string const left = (p_left == nullptr? "" : p_left->to_string());
string const right = (p_right == nullptr? "" : p_right->to_string());
return "(" + left + " " + to_string( value ) + " " + right + ")";
}
~Node() { delete p_left; delete p_right; }
};
Node* root_;
Tree( Tree const& ) = delete;
Tree& operator=( Tree const& ) = delete;
public:
auto is_empty() const -> bool { return (root_ == nullptr); }
void insert( T const data )
{
Node** pp = &root_;
while( *pp != nullptr )
{
auto const p = *pp;
pp = (data < p->value? &p->p_left : &p->p_right);
}
*pp = new Node{ data, nullptr, nullptr };
}
auto minValue() const -> T
{
assert( root_ != nullptr );
Node* p = root_;
while( p->p_left != nullptr ) { p = p->p_left; }
return p->value;
}
auto maxValue() const -> T
{
assert( root_ != nullptr );
Node* p = root_;
while( p->p_right != nullptr ) { p = p->p_right; }
return p->value;
}
auto to_string() const -> string
{
return (root_ == nullptr? "" : root_->to_string());
}
~Tree() { delete root_; }
Tree(): root_( nullptr ) {}
Tree( Tree&& other ): root_( other.root_ ) { other.root_ = nullptr; }
};
} // namespace my
auto main() -> int
{
my::Tree<int> tree;
for( int const x : {5, 3, 4, 2, 7, 6, 1, 8} )
{
tree.insert( x );
}
using std::cout; using std::endl;
cout << tree.to_string() << endl;
cout << "min = " << tree.minValue() << ", max = " << tree.maxValue() << endl;
}
Output:
(((( 1 ) 2 ) 3 ( 4 )) 5 (( 6 ) 7 ( 8 )))
min = 1, max = 8
i have a little problem with my code in c++.. I need to doit this way, because it's work to school..
I have template named Catalog
template <typename T>
class Catalog
{
struct Item{
T* _product;
unsigned int _amount;
Item* _next = nullptr;
};
Item* _head;
Item* _actual;
Item* _last;
int _size;
void init()
{
this->_size = 0;
this->_head = nullptr;
this->_actual = nullptr;
};
public:
Catalog(void)
{
this->init();
};
T*& operator[](unsigned int){
Item* node = this->_head;
for (int i = 0; i < this->_size; i++)
{
if (i == pos)
{
return &node->_product;
}
node = node->_next;
}
return nullptr;
};
};
It's a structure where i have Items and in Items i have pointer to next one in array..
I tryed to like this
Catalog<Products> *catalog = new Catalog<Products>();
Products *pr1 = new ProductA(5, "jmeno", 5);
catalog->Add(pr1, 5);
Products* ct = catalog[0];
In my case visual studio is reporting this error
IntelliSense: no suitable conversion function from SemestralniPrace::Catalog<Products>" to "Products *" exists
I want to correct operator[] so i can use my catalog like i need to.. or correct the code in main..
It's for example, i have some more functions in class Catalog, but it isn't importnent for this problem..
Can someone help me please.. Even suggestions is good for me. I am desperate with this.
Thanks and sorry for my English, it's not mine native language.
You have two mistakes. The first one is relative to the return statement of the operator []. The type of expression &node->_product is T** while the return type of the operator is T*&
You have to write simply
return node->_product;
The second mistake is relative to statement
Products* ct = catalog[0];
You have to write either
Products* ct = ( *catalog )[0];
or
Products* ct = catalog[0][0];
specifically I have a list of objects of a class with multiple string object data members(NID, customerNumber, studentNumber, fName, lName).
I want to reuse the following code to search for the node that matches the search key whether the data member that is looked for is NID or any other of the class's string data members.
nodePtr = firstPtr;
for(; nodePtr != NULL && nodePtr->str != str; nodePtr = nodePtr->nextPtr);
if(nodePtr != NULL)
//the nodePtr points to the node that matches the search key
else
//no node matched the search key
if it was PHP code I could use the value of a variable as the name of another:
$node->${$var}
but in C++ is there anyway to reuse the code?
The most flexible way to do this is to provide a predicate as a template parameter:
template <typename Pred>
Node * find_if(Node * node, Pred pred) {
for (; node && !pred(node); node = node->next);
return node;
}
In C++11, you can call it with a lambda:
if (Node * node = find_if(first, [&](Node * n){return n->NID == nid;})) {
// node points to the matching node
} else {
// not found
}
or, if you're stuck in ages past, a function object:
struct CompareNID {
CompareNID(std::string nid) : nid(nid) {}
bool operator() {Node * n) {return n->NID == nid;}
std::string nid;
};
Node * node = find_if(first, CompareNID(nid));
or, since all your fields are strings, you could sacrifice flexibility for tersity using member pointers, giving something similar to your PHP example:
Node * find(Node * node, std::string Node::*member, std::string const & value) {
for (; node && node->*member != value; node = node->next);
return node;
}
Node * node = find(first, &Node::NID, nid);
Similar to std::find_if:
template<typename N, typename P>
N* my_find_if(const N* head, P pred)
{
N* ptr;
for (ptr = head; ptr != nullptr && !pred(ptr); ptr = ptr->nextPtr)
;
return ptr;
}
Can be called like this:
my_find_if(firstPtr,
[](Node* node){ return node->str == str; });
Change the lambda to whatever expression you need.
Of course, I would rather recommend you to use the standard containers instead of creating your own list. Then you could use the standard std::find_if instead.
Yes, you want to pass in 2 lambdas (C++11) or runnable objects (C++03) into your "find" algorithm.
With C++03 you might pass in 2 boost functions, one for the "found" case and one for the "not found" case.
void search( std::string str,
boost::function<void()> ifFound,
boost::function<void()> ifNotFound )
{
//search
if( nodePtr != NULL )
{
ifFound();
}
else
{
ifNotFound();
}
}
Choose your function signatures to match, but that's how you pass in the dynamic functions.
You could use std::function instead of boost::function.
If it's the searching itself you want to make flexible, i.e. what part of your object you are trying to match, use also a dynamic predicate.
void search( Pred pred// , ifFound, ,ifNotFound )
{
if( pred( nodePtr ) ) // then it is found
}
The predicate, as you see, will take a node-pointer and will return true/false. Thus different predicates would be used to match different data members.
If you really like the concept of "reusable code" though, I would suggest you use the standard library.
If your lists are long and you are continually doing these searches, manual search is slow and you could use a boost::multi_index to create log-N time look-ups on your various fields.
Maybe you want to use pointer-to-members:
typedef string Node::*NodeStringPtr;
NodeStringPtr nodeStrPtr = nullptr;
std::vector<NodeStringPtr> nodeStrings {&Node::NID, &Node::str, &Node::fName};
for (auto& ptr : nodeStrings)
{
nodePtr = firstPtr;
for (; nodePtr != NULL && nodePtr->*ptr != str; nodePtr = nodePtr->nextPtr);
if (nodePtr)
{
nodeStrPtr = ptr;
break;
}
}
if(nodePtr != NULL)
//the nodePtr matches the search key, nodeStrPtr matches the element
else
/* ...*/
One other way is to use pointers to members (only possible if all the members are of the same type):
struct Item {
std::string NID,
customerNumber,
studentNumber,
fName,
lName;
};
typedef std::vector<Item>::iterator nodePtr;
typedef std::string Item::* MemberPtr;
struct List {
std::vector<Item> list;
nodePtr search(const std::string& str, MemberPtr mem_ptr)
{
// this is the code you want to reuse, I took the liberty and used
// standard lib's algorithm
return std::find_if(list.begin(), list.end(),
[&](const Item& item){ return str == item.*mem_ptr; });
// will return list.end() if it doesn't find anything
}
};
int main()
{
List lst;
lst.search("John", &Item::fName);
lst.search("Doe", &Item::lName);
lst.search("42", &Item::customerNumber);
}
I think this is the closest you can get to your PHP example.