I'm implementing a min heap with an extra property of saving the max key between the children.
I have a Node class, and in case the Node is a leaf I want it to point back to itself.
Something like:
class Node
{
public:
void update max()
{
if ((left==NULL)&&(right==NULL))
max=this;
}
private:
Key* key;
Value* val;
Node* left;
Node* right;
Node* max;
}
The reason is that right now it points to NULL and it makes me check too many times if max is NULL before comparing the Keys.
I should also mention that I'm using all these pointers since Key and Value are pure virtual, and Node has a derived class which I'll be using.
Anyway.. Is it possible to have a member variable pointing to this?
This is by definition the reference/pointer to the object that the object holds itself. Nothing forbids you to save that reference value into something else
Related
I created a link list and an integer field to represent the linked list.
Then I assigned the integer field to 0.
I don't know how to convert the int parameter into the linked list.
template<typename T>
struct Node{
T data;
Node* next;
};
class Integer{
private:
Node<int>* real_num;
public:
Integer(){
real_num->data = 0;
std::cout << "success!";
}
Integer(int int_convert){
real_num->data = int_convert;
}
The constructor assigns a value to a variable in a structure which has been declared but not itself constructed.
Add this to the top of your constructors.
Node<int> * real_num=new Node<int>;
Only after the Node has had memory allocated, etc is it valid to reference a variable in the struct that real_num only points to. Without 'new' real_num points to null.
You should take a look at std::list which is a container that represents a double-linked list.
If it doesn't answer your problem, so far your code is correct. You now need to add getter and setter and also utility functions to manipulate your linked list.
Edit: You have to construct your private variable before using it or will run into a undefined behavior because you gonna use a memory part that hasn't been initialized. If you are lucky enough, your program will crash and end up with a Segmentation Fault.
Take a look at the keyword new and delete to allocate/deallocate memory in C++.
Here is my class
struct Node
{
int val;
vector<Node*> children;
Node() :val(0), children({}){};
Node(int _val) :val(_val) {};
};
And I build a map
map<int,Node*> dict;
I know that the pointer object will not call for the constructor of class, so if the key i does not exist in map, we are not allowed to use the code like:
dict[i]->val = i;
instead, we should do like
if (!dict.count(i))
{
Node* node = new Node(i);
dict[i] = node;
}
So is it possible to modify the definition of class to allowed us to do dict[i]->val = i for the nonexistent key.
No, there is no way to make value initialised pointer to be a valid pointer to object, and that is what you will always get for objects created by std::map::operator[]. Such pointer is always null.
Instead of storing a pointer to node, you could store the node itself in the map element. The syntax of accessing the elements would be different, but you would achieve what you want otherwise:
map<int,Node> dict;
dict[i].val = i; // map now contains a node
operator[] does insert an element when it finds none for the given key and it does not tell you if there was an element before. Note that it has quite different semantics from the "usual" operator[]. For example in a vector you can only access elements that exist in the vector. Thats a different operator[].
Count will not give you an iterator to the element if it exists. If you want use the element whether it was present or not, you can use find (and insert if necessary):
auto it = dict.find(i);
if ( it == dict.end() ) {
it = dict.insert( { i, new Node() } ).first;
}
it->second->val = i;
However, don't do this. Store Nodes in the map instead of pointers. If you need pointers use smart pointers.
Everything is possible, but not simple.
So to be sure the pointer points to something you need to make a pointer class that if default constructed instantiate a node.
template <typename Node>
class IAmNotNull : public std::unique_ptr<Node> { // just inherit unique_ptr because I'm lazy.
public:
using std::unique_ptr<Node>::unique_ptr<Node>; // use base ctor
IAmNotNull() :: std::unique_ptr(new Node) { // call base ctor.
} // overrides base default ctor
}
All bugs are your own if you try to use this.
When using a linked list that stores numerous objects how would you go about access the data inside said object?.
Example code.
using namespace std;
typedef struct node
{
int data;
node* next;
} *nodePtr;
nodePtr head;
nodePtr current;
nodePtr temp;
void PrintList()
{
current = head;
while(current != NULL)
{
cout << current->data.getMakeModel();
cout << current->data.getRegNo();
cout << current->data.getEngineSize();
cout << current->data.getRented();
current=current->next;
}
}
My current way of doing it doesn't work and I'm not sure how to solve it.
All i need to do is access the template object data members which i have getter methods for and output the data.
Any ideas?
On a side note, would it be possible to search for a specific object(an object with specific data member value) in a linked list? with the objects still using templates of course
When using a linked list that stores numerous objects how would you go about access the data inside said object?
If you have a nodePtr you'll have to do ptr->data to access the int of the struct.
My current way of doing it doesn't work and I'm not sure how to solve it.
You are trying to access member functions on an object of type int, that does not have any. You probably meant to define another type for the data member object of node.
On a side note, would it be possible to search for a specific object(an object with specific data member value) in a linked list?
Of course, the implementation of such an algorithm is pretty trivial. You can implement it along the lines of:
nodePtr find(nodePtr head, int value) {
for (; head != NULL; head = head->next)
if (*head == value)
return first;
return NULL;
}
What I would suggest is to use the standard std::forward_list or std::list. If you do, you'll be able to use std::find for the "find"-algorithm.
The probem here is that data is of type int and not of a class type. You will have to change its type to a class type e.g Foo. A more advanced solution will use templates to make it work with arbitrary types (e.g std::list)
Also notice that your class definition is not considered good style. I would define it as:
struct node
{
typedef node* Ptr;
Foo data;
node* next;
};
While the typedef is only reasonable in some special cases (e.g if working extensively with smart pointers and reference counting). In normal cases one should go with node* (which is also smaller o.O)
I have a uni assignment in which I have to implement a singly linked list that contains different objects that are derived from a common abstract base class called Shape.
I'll link to GitHub for the class implementation: shapes.h , shapes.cpp. So far it consists of Shape and its derived class Circle. There'll also be Rectangle, Point and Polygon later.
I should now implement a singly linked list of these different kinds of shapes. So far I've come up with the following class prototype for the List-class and the Node-class:
class Node
{
public:
Node() {}
friend class ShapeList;
private:
Shape* data;
Node* nextNode;
};
class ShapeList
{
public:
ShapeList(){head = NULL;}
void Append(Shape& inData);
private:
Node* head;
};
Adding elements void Append(Shape& inData) to a ShapeList-object should be able to be called from main in the following style:
ShapeList list1;
list1.Append( Circle(5,5,5) );
list1.Append( Rectangle( 4, 10, 2, 4) );
Given this information, how should I go about implementing void Append(Shape& inData)? I've tried several different approaches, but haven't come up with the correct solution so far.
It's also completely possible that the parameter to Append should be something else than (Shape& inData).
edit:
I've implemented Append(Shape& inData) but it works only sometimes:
Circle circle1;
ShapeList list1;
list1.Append( circle1 );
but not with
ShapeList list1;
list1.Append ( Circle(5,5,5) )
So far my Append()-implementation looks as follows:
void ShapeList::Append(Shape& inData)
{
//Create a new node
Node* newNode = new Node();
newNode->data=&inData;
newNode->nextNode=NULL;
//Create a temp pointer
Node *tmp = head;
if (tmp != NULL)
{
//Nodes already present in the list
//Traverse to the end of the list
while(tmp->nextNode != NULL)
tmp = tmp->nextNode;
tmp->nextNode=newNode;
}
else
head=newNode;
}
Does that look ok to you guys?
Since this is tagged under 'homework', I will only point you to the good direction. This may be too basic or maybe it is enough for your needs...
In a typical situation, you would simply use a container that is already written such as std::list.
But for implementing your own linked list
When you start from the head member of the ShapeList, you should be able to traverse the entire list and find a node for which 'nextNode' has never been assigned.
This is where you want to add a new node.
Now thee a a few tricks to be make things work:
1- In C++, variables are not automatically initialized. You must therefore initialize the many values when you create a new node, especially the next node pointer.
2- Instead of having pointers to references, I suggest that either you create copies of Shapes, of use some kind of smart pointers to avoid copying.
3- Don't forget about memory management, when you destroy your linked list, you will have to destroy all nodes individually since.
One very nice implementation of the singly linked list is as a circular list with the "head" pointer pointing at the tail. This makes it easy to insert at either the front or append to the end: in either case you create a fresh node, make the current tail point to it, and make it point to the current head, and then in the insert case make the head pointer point to the new node.
What you appear to be missing (other than what's already been pointed out: allocating, deallocating, and copying the nodes) is a way to know that you've actually created the list. So you'll want to add in some sort of output - either an operator << or a print() routine, which will walk the list, and call your graphical objects' printing mechanisms in order.
You say that it is possible that the argument to Append might not be Shape &data. Given the requirement of the calling convention specified, it should be:
Append( const Shape &data ) // provided shapes have copy constructors
{
Node *newNode = new Node( data ); // requires a constructor of Node that copies data to a freshly allocated location and sticks a pointer to that location in its data field - then Node's destructor needs to release that pointer.
... ( and the code to manipulate the existing list and newNode's next pointer )
}
Among other things this makes responsibility for management clear and simple.
If you have a Node constructor that takes both a pointer to a Node and a Shape, you should be able to do Append in two lines - one allocating the new Node and calling the constructor appropriately, and one modifying a pointer to point to the new node.
I would add - based on your edit - that you absolutely need to do the allocation and copy inside Append.
You probably want Node to be nested inside of ShapeList so its full name will be ShapeList::Node, not just ::Node.
Since Node will own some data remotely, you probably need to define the big three for it.
In line with that, when you push something onto the list, the list will hold a dynamically allocated copy, not the original object.
Edit: Append should take a Shape const & rather than a Shape &. A reference to const can bind to a temporary object, but a reference to non-const cannot, so the calls using parameters that create temporary objects (e.g., list.Append(Circle(5,5,5))) won't compile if the parameter is a reference to non-const object.
I'd also change Node::Node to require that you pass it a parameter or two. As-is, your linked-list code is dealing with the internals of a Node more than I'd like. I'd change it to something like:
Node::Node(Shape const *d, Node *n=NULL) : data(d), nextNode(n) {}
Then in append, instead of:
Node* newNode = new Node();
newNode->data=&inData;
newNode->nextNode=NULL;
You'd use something like:
Node *newNode = new Node(&inData); // or, probably, `... = new Node(inData.clone());`
...and Node's ctor would handle things from there.
Also note that it's easier to add to the beginning of a linked list than to the end (it saves you from walking the whole list). If you really want to add to the end, it's probably worthwhile to save a pointer to the last node you added, so you can go directly to the end, rather than walking the whole list every time.
Here is one way to handle the polymorphic requirement (std::shared_ptr), demonstrated with the STL singly linked list...
typedef forward_list<shared_ptr<Shape>> ShapeList;
ShapeList list1;
list1.push_back(make_shared<Circle>(5,5,5));
list1.push_back(make_shared<Rectangle>(4, 10, 2, 4));
Here is how it would effect Node:
class Node
{
public:
Node() {}
friend class ShapeList;
private:
shared_ptr<Shape> data;
Node* nextNode;
};
and ShapeList...
class ShapeList
{
public:
ShapeList(){head = NULL;}
void Append(const shared_ptr<Shape>& inData);
private:
Node* head;
};
in Line 3 "Node next;" the Compiler gives me an incomplete type error. I think it treat it as a member function not an Attribute. What's wrong in that Definition?
class Node {
private:
Node next;
Node previous;
int value;
int min;
public:
Node(int value) {
this.value = value;
this.min = value;
}
void insert(Node node) {
if (this.next != null) {
this.next.insert(node);
}
else {
this.next = node;
node.previous = this;
}
}
}
First of all, this is a pointer, not a reference, so you need to replace all this. with this->.
Secondly, you cannot store an instance of a class inside that class because the size of the class would be incalculable. You can only store pointers or references to the class inside the class itself, because the compiler can calculate the size of a pointer or reference to any class without having to have any details of the class (because these pointers/references are all the same size regardless of the underlying object). Change
Node next;
Node previous;
to
Node* next;
Node* previous;
// or Node* next, *prev;
And change
void insert(Node node)
to
void insert(Node* node)
You also need to initialise the member pointers to NULL (not null) in the constructor of your object (because C++ doesn't initialise variables that are intrinsic (built-in) types (like pointers) for you):
Node(int value) {
this->previous = NULL;
this->next = NULL; // or: previous = next = NULL;
this->value = value;
this->min = value; // or: this->value = min = value;
}
// or with initialiser lists (but don't get confused if you don't understand)
// Node(int value) : previous(), next(), value(value), min(value) { }
Additionally, I (like everyone else) have deduced (from your use of objects like they are references and your use null instead of NULL and of the words 'method' and 'attribute') that you are a Java or C# programmer learning C++. Please stop now and read a good book on C++, because C++ is nothing like Java or C#, and if you try to use your C#/Java experience when programming C++ then you will only end up ripping your own head off out of frustration.
Work with pointers, not objects.
Node * next;
Node * previous;
then
Node(int value) : next(NULL), previous(NULL) {/**/}
then
void insert(Node * node) {/**/}
It looks like you're trying to write Java/C# in C++!
In C++, objects are stored by value, not by reference. So in something like this:
class Node {
Node next;
};
you're asking for a Node to store another Node inside it, which would require an infinite amount of storage.
Perhaps you want to store pointers to the next and previous nodes.
You can't nest objects like that. Think about it -- what is the size of Node? Well, since each Node contains exactly 2 other Nodes, it means it would have infinite size.
You need a way to make your children null, so the solution is to use Node* instead of Node.
C++ does not have a concept of "class attributes". Any variable declared at class scope is a (possibly static) member. Therefore, a class that contains a member of its own type is an absurdity. For example,
struct S {
S s;
int i;
};
being legal would mean that sizeof(S) == sizeof(S) + sizeof(int), ignoring padding. As this clearly cannot be the case, it is forbidden.
If you want a Node to have pointers to other Nodes (which you probably do), you should give it Node* members. You should also be passing a Node* to insert, as opposed to a Node*.
By the way, C++ does not generally have null defined like C# does. You can compare pointers to NULL, 0, or nullptr.
The class Node is being defined and while doing so, you cannot define any member of type Node, because the size of Node is not yet determined. Just think, how would compiler computer the size of Node? To compute sizeof(Node), the compiler needs to know the size of each of its members, but two of its members are of type Node itself whose size is being computed.
The solution is to define them as pointer :
Node *next;
Node *previous;
Now the size of Node is computable, as size of each of its members is already known. Note that size of pointer of any type is equal to sizeof(void*)1, which means sizeof(Node*) is equal to sizeof(void*) which is known.
1. Except sizeof(pointer-to-member) could be different from sizeof(void*). Technically, for many compilers, pointer-to-member is not pointer to begin with; they are different animals.