Creating a custom Linked List C++ - c++

I have started learning C++ recently and am currently trying to make my own double linked list. I don't know how it is supposed to be done. Am I suppose to use the already existing list class to store my data and keys or create my own node and linked list class. Or should I just use linked lists that C uses?

The node structure and the container structure is different.
Single linked list:
struct node{
node* next;
int data; // Not necessarily an int, but whatever the node will contain.
};
struct container{
node* head;
};
Double linked list:
struct node{
node* next;
node* prev; // Unlike the single linked list, a double linked list's node contains a pointer to the previous element as well.
};
struct container{
node* head;
node* tail;
};
Keep in mind that when you're performing any operation (i.e. push, pop, pull, etc.) you will have to take both of these pointers into consideration.

Related

Doubly linked list constructor with vector inside c++

I am new to c++ and am working on an assignment involving vectors and a doubly linked list. I am given this struct as such.
struct Node {
std::vector<T> data;
Node<T>* next;
Node<T>* prev;
Node(): next(nullptr), prev(nullptr){} };
I am now required in another class to create a constructor for this Node to be used for various methods. I understand that the struct already has an initialization list for next and prev, I think I am just overthinking what the constructor should be.
Class LinkedVector {
Node<T>* head;
LinkedVector<T>::LinkedVector(){
head = NULL;
}
}
Is this the correct way of constructing the linked list? Again I am new to c++ and any help pointing me in the right direction is most helpful. Thank you and have a great day.
Yes, that is almost correct, you want to set head to nullptr instead of NULL of course.
Then when you create methods to add to the list you will need to check if it is empty and if so initialize head rather than adding an element elsewhere.

Why can't I define two member pointers that are the same type of the class in the same row

This code generates error like below
error: field 'next' has incomplete type 'Node'
class Node {
public:
Node(int k, int v) {
key = k;
val = v;
}
public:
Node* prev, next;
int key, val;
};
Change Node* to int won't have the same complain. Put prev and next into separate lines solves the error.
Why can't I define two member pointers that are the same type of the class in the same row?
The asterisk (*) belongs with the variable name. Node is the datatype. In effect, you've defined:
Node *prev;
Node next;
Add an asterisk in front of next, e.g. *next.
The error relates to the fact that in doing so, you've failed to initialise the instance of Node stored in next. prev is a pointer and doesn't need to be initialised.
You can, you have to do following:
Node* prev,* next;
People usually get confused by this notation:
Node* prev, next;
Thinking they declared 2 pointers, but instead they declared a pointer * next and instance of a node, and thinking that this is the same as
Node* prev;
Node* next;
but it is not, it is the same as
Node* prev;
Node next;
I would suggest using
Node *prev, *next;
and always remember that for every pointer declared you need * in front of it.
Although it is good practice to write Node* prev, with the asterisk aligned to the left, a multi-variable declaration is the one edge case exposing the fact that the C++ grammar (largely inherited from C) doesn't see it that way. It "binds" the * to the name, not to the type, so it "looks like" Node *prev internally.
As a consequence, you have actually created:
Node* prev;
Node next;
… the second declaration being impossible as you're inside the Node definition.
You could fix it this way:
Node *prev, *next;
Or this way:
Node* prev, *next;
But the latter is internally inconsistent in style, and the former is inconsistent with a left-alignment used elsewhere in your code. Of course you could start right-aligning your asterisks everywhere to re-introduce consistency, but that has many more downsides that aren't worth it for this one edge case.
What I think you really should do is just split the declaration into two:
Node* prev;
Node* next;
This is arguably neater anyway.

confusion in basics of linklist

I was going through the linked list and I have confusion. maybe I am mixing the concept or something else. Here is the code of creating the header node.
struct node
{
int data;
struct node *link;
};
node *head;
void main()
{
head = new node;
}
1)The first thing I want to know is how can we write struct node *link; in inside the same node structure? because using first the node structure is created then we can declare pointer of that.
2) node *head; will already declare a memory of size node, then we need to do again head = new node;?
The self referential struct can hold a pointer to itself. Please do not confuse with size of pointer to size of structure. Size of pointer is constant irrespective of data type.
struct node
{
int data;
struct node *link;
};
Had it the struct node *link be something else like struct node link, It will not compile just like you think.
regarding why allocation by using the new is required, when we do node *head, it says that head points to memory location of actual node with area for data and link.
It might be useful to read pointer concept again
A link list is a chain of objects. What you are doing here is creating a struct with two variables. One is the date to store in this node. The other is a recursive struct. This where link lists get their name. One struct links to the next. When this node is created, link has no value but you can add nodes by creating a new node and storing it in link.
As for the rest of your code, I don't think you are doing it right. Usually nodes are wrapped in a link list class so that you can control the link list by adding, deleting and searching the nodes. When you are controlling a link list you need at least two pointers. One to point to the first node in the list (also called the "head"). The second pointer is the search pointer that will start at the head and go node by node until you find what you are looking for.
Now to answer your second question when you write node* head you are only declaring the pointer. You are not declaring "a memory of size node" so in the initialize function of the link list you need to create the first node and have the head point to it head = new node;

Why the first node of a linked list is declared as a pointer?

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.

C++: Linked List Representation

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.