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.
Related
Suppose we have class for linked list of T.
(I don't know if code actually works)
template <typename T>
struct List{
struct Node{
T data;
Node *next;
};
// add, remove etc...
Node *locate(const T &a) const{
for(Node *node = head; node; node = node->next)
if (node->data == a)
return node;
return nullptr;
}
private;
Node *head;
};
If you inspect method locate, it basically can harm and ruin the linked list, even the method is marked as const.
I just noticed something else. Since Node is not const, Node::data can be changed as well.
Supposing this was programmer mistake, is there a C++ way this to be avoid?
I know the method can be written as this.
const Node *locateConst(const T &a) const{
for(const Node *node = head; node; node = node->next)
if (node->data == a)
return node;
return nullptr;
}
You are seeking an experimental feature, yet unavailable on many platforms. If your std libray supports, you can use std::experimental::propagate_const<node*> instead of naked raw pointers.
https://en.cppreference.com/w/cpp/experimental/propagate_const
In the mean time, you can implement your - maybe less generic - own version.
In C++, "const" means "can't change this object", it does NOT mean "can't change things this object points to".
I.e. with const List *const_list you can't change const_list->head, but you can change const_list->head->next or const_list->head->data.
If you're writing a List class, then you probably want const List to mean "can't change things this object points to", and C++ provides the tools you need to implement List so it works that way. But it's your job, as the author of the List class, to do that - the compiler can't just magically know that's what you intended.
is there a C++ way this to be avoid?
No, of course not. Programmers do have responsibilities you know. The way the method is declared promises not to change head, not *head.
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
Now I know that why pointers are used in defining linked lists. Simply because structure cannot have a recursive definition and if there would have been no pointers, the compiler won't be able to calculate the size of the node structure.
struct list{
int data;
struct list* next; // this is fine
};
But confusion creeps up when I declare the first node of the linked list as:
struct list* head;
Why this has to be a pointer? Can't it be simply declared as
struct list head;
and the address of this used for further uses? Please clarify my doubt.
There's no definitive answer to this question. You can do it either way. The answer to this question depends on how you want to organize your linked list and how you want to represent an empty list.
You have two choices:
A list without a "dummy" head element. In this case the empty list is represented by null in head pointer
struct list* head = NULL;
So this is the answer to your question: we declare it as a pointer to be able to represent an empty list by setting head pointer to null.
A list with a "dummy" head element. In this case the first element of the list is not used to store actual user data: it simply serves as a starting "dummy" element of the list. It is declared as
struct list head = { 0 };
The above represents an empty list, since head.next is null and head object itself "does not count".
I.e. you can declare it that way, if you so desire. Just keep in mind that head is not really a list element. The actual elements begin after head.
And, as always, keep in mind that when you use non-dynamically-allocated objects, the lifetime of those objects is governed by scoping rules. If you want to override these rules and control the objects' lifetimes manually, then you have no other choice but to allocate them dynamically and, therefore, use pointers.
You can declare a list such a way
struct list head = {};
But there will be some difficulties in the realization of functions that access the list. They have to take into account that the first node is not used as other nodes of the list and data member of the first node data also is not used.
Usually the list is declared the following way
struct List
{
// some other stuff as for example constructors and member functions
struct node
{
int data;
struct node* next; // this is fine
} head;
};
and
List list = {};
Or in C++ you could write simply
struct List
{
// some other stuff as for example constructors and member functions
struct node
{
int data;
struct node* next; // this is fine
} head = nullptr;
};
List list;
Of course you could define the default constructor of the List yourself.
In this case for example to check whether the list is empty it is enough to define the following member function
struct List
{
bool empty() const { return head == nullptr; }
// some other stuff as for example constructors and member functions
struct node
{
int data;
struct node* next; // this is fine
} head;
};
In simple terms, if your head is the start node of the linked list, then it will only contain the address of the first node from where linked list will begin. This is done to avoid confusion for a general programmer. Since the head will contain only address, hence, it is declared as a pointer. But the way you want to declare is also fine, just code accordingly. Tip: If you later on want to make some changes in your linked list, like deletion or insertion operations at the beginning of the linked list, you will face problems as you will require another pointer variable. So its better to declare the first node as pointer.
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)
The way I know how to represent a linked list is basically creating a Node class (more preferably a struct), and the creating the actual linkedList class. However, yesterday I was searching for the logic of reversing a singly linked list operation and almost 90% of the solutions I've encountered was including that the function, returning data type Node* . Thus I got confused since if you want to reverse a list no matter what operation you done, wouldn't it be in the type of linkedList again? Am I doing it the wrong way?
The linked list implementation I do all the time;
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *next;
};
class linkedList
{
public:
Node* firstPtr;
Node* lastPtr;
linkedList()
{
firstPtr=lastPtr=NULL;
}
void insert(int value)
{
Node* newNode=new Node;
newNode->data=value;
if(firstPtr==NULL)
firstPtr=lastPtr=newNode;
else {
newNode->next=firstPtr;
firstPtr=newNode;
}
}
void print()
{
Node *temp=firstPtr;
while(temp!=NULL)
{
cout<<temp->data<<" ";
temp=temp->next;
}
}
};
You approach isn't wrong, but you might be giving too much emphasis on your linkedList class.
What does that class actually contain? A pointer to the first node, and a pointer to the last node (which is redundant information, since you can find the last node by only knowing the first one). So basically linkedList is just a helper class with no extra information.
The member functions from linkedList could easily be moved inside Node or made free functions that take a Node as parameter.
Well, what is a linked list but a pointer to the first node? A list is fully accessible provided you can get to the first node, and all you need for that is a pointer to the first node.
Unless you want to store extra control information about the list (such as its length for example), there's no need for a separate data type for the list itself.
Now some implementations (such as yours) may also store a pointer to the last node in the list for efficiency, allowing you to append an item in O(1) instead of O(n). But that's an extra feature for the list, not a requirement of lists in general.
Those functions might be returning of type Node* because after reversing the linked-list they will return the pointer to the First node of the list.