Struct node
{ char name [30];
int length;
node * next;
};
Using dynamic memory allocation how will i use the struct above to create a list to hold any number of nodes? without knowing that number beforehand.
Please read through this simple and quick tutorial on Singly linked lists in C++
Related
I am trying to create a graph using linked list styled nodes where each node is a structure containing a key and an address to the next node, but I want to join multiple nodes to one node so I tried creating an array of pointers to structure and initialize them using new dynamically but it throws an error saying that it "cannot convert node*** to node** in assignment".
I have tried using struct node* next[] but it didn't work well. What am I missing here? Should I just use a vector of pointers instead of an array?
struct node
{
int key;
struct node** next;
};
int main()
{
struct node A;
A.key = 12;
A.next = new node**[2];
return 0;
}
Should I just use a vector of pointers instead of an array?
This is often an ideal solution. This would fix the memory leak that your program has (or would have if it compiled in the first place). An example:
struct node
{
int key;
std::vector<node*> next;
};
// usage
A.next.resize(2);
Vector does have space overhead, which can be a problem with big graphs because the total overhead increases linearly in relation to number of nodes. If vector is not appropriate for you, an alternative is std::unique_ptr, which does not have any overhead compared to a bare pointer:
struct node
{
int key;
std::unique_ptr<node[]> next;
};
// usage
A.next.reset(new node*[2]);
new node**[2];
What am I missing here?
You're attempting to create an array of node** when you need an array of node*.
Should I just use a vector of pointers instead of an array?
YES!
After including the vector library, then in your structure, you would have a member like this:
std::vector<node*> next;
This is the C++ approach, using raw pointers is the C approach.
As an encyclopedian information though, with raw pointers, you would do:
A.next = new node*[2];
which means an array of two pointers.
I want to have a linked list, with a variable which has dynamic size,
because I want to just allocate different sizes for a variable in different nodes. for example node1 has a array variable with size 1, but node 2 has a array variable with size 10, and node3 never allocates this array.
like this:
struct st{
int * var_dynamic;
int x;
};
now I want to initialize them. for the static one, it is like this:
struct st st1;
st1.x=1;
but how can I initialize the dynamic one?
Is it something like this?
st1.var_dynamic= new int [100];
and if yes, Is this way correct and efficient?
The most idiomatic, straightforward, and safe solution is to simply use std::vector:
struct st
{
std::vector<int> var_dynamic;
int x;
};
For using std::vector, consult a reference documentation, or your favourite book.
I am trying to perform certain operations through linked lists on vectors.
We have been given a struct type vector
typedef struct{
int *array; // a pointer to vector's storage
int size; // the current number of elements in the vector
int cap; // the current capacity of the vector;
int init_cap; // the initial capacity the vector was initialised with.
} vector;
Now, I want to make a function that takes in a pointer to the vector struct, and initialises it with the given capacity. All the fields are to be initialised. I want to do this using linked list.
Here is my code
#include <iostream>
using namespace std;
typedef struct node {
int *array; // a pointer to the vector's storage
int size; // the current number of elements in the vector
int cap; // the current capacity of the vector
int init_cap; // the initial capacity the vector was initialised with
node *next;
} vector;
node *head = NULL;
Can I make nodes from a vector struct, like I have attempted in the code written above?
void vector_init(vector *v, int capacity){
//initialising the vector with the given capacity
v->size = capacity;
v->cap = capacity;
v->init_cap = capacity;
//linked list with nodes created and values initialised
node *temp, temp2;
temp = head;
temp = new node;
temp->size = capacity;
temp->cap = capacity;
temp->init_cap = capacity;
temp->next = temp2
temp2 = new node;
temp2->size = capacity;
temp2->cap = capacity;
temp2->init_cap = capacity;
temp2->next = NULL;
}
Have I made the linked list, and initialised the values correctly? If we do not create temporary points temp and temp2, and just use v->size etc to initialise the fields, would that make it a linked list?
You have many problems with your code.
Don't use the name vector - there is a structure called std::vector and it is easy to get confused.
If you want to initialize the values of the structure, don't create an external, separate function for that - it's not c++'ish. Create a struct constructor initializing all the values instead.
You don't initialize the array variable anywhere in your code. You should allocate space for it depending on the capacity given in the constructor.
Don't use the name 'array' for the variable. There is a structure called std::array in C++, and it might be confusing.
Your implementaion makes very little sense to me. You have a linked list of arrays right now; if you would like to functionally replace an array of ints with a linked list of ints, each node should contain one int value.
If, for some reason, you would want to stick to this implementation, you also need some kind of update function that would automatically update size and cap variables while adding or removing elements from array. Otherwise you are sure to end up forgetting about it and you're gonna have mess in your structure. Make this function a part of the structure - it shouldn't be an external function.
That typedef struct node doesn't make sense even after changing the word vector to something else - you don't use it anyway in your code.
You are using the same name for two different structures; vector is at first defined as having 4 fields, and in the next lines as having 5 fields.
Technically yes, this is a linked list, but your vector_init() function does not work as it should. Apart from what I've written above:
You should avoid making functions depend on the global variable, in this case head. It could be passed as a parameter.
These two lines:
temp = head;
temp = new node;
don't make sense. The first one makes the variable temp point to head; the second one tells temp to start pointing to the new variable as you're using operator new, which allocates space and return a pointer to the newly created variable. As a result, you don't operate on the variable head, when you do further operations, but on another variable that will be lost after the temp pointer gets invalidated.
You don't need temp and temp2 variables at all. They only bloat the code.
These two lines:
temp->next = temp2;
temp2 = new node;
should switch places since now you assign a pointer that hasn't been yet initialised.
After writing all this stuff I've realised that the function is incorrect in general. For some reason, you first work on the parameter v, and then do something unrelated to it.
Also, your instructor is just not right saying that you can solve all types of problems with the use of linked lists. It may solve some problems in certain situations, or create new problems, depending on the context.
I don't want to be rude, but there seems to be something fundamentally wrong with the concept of the task you have been given itself. I guess someone really hasn't thought it through.
Suppose you have a linked list of nodes as defined below:
C++ code
struct node {
node *next;
int i ;
};
Is there any benefit in making the next pointer as the first member variable of the structure ?
I think that people try this via the above approach (I may be wrong here)
node n, m;
*n=&m;
If above is right, is it right to code like above. What's the right way?
Is there any benefit in making the next pointer as the first member
variable of the structure ?
A very small performance benefit can be reached to reduce the assembly instruction size in loads from and writes to zero offset members, but only in classes without virtual table (vtbl is a omitted first member).
If you want prebuild a scope/global allocated list, its elements can be initialized as mentioned.
You can try it:
struct node {
struct node* next;
int i;
};
node z = {0}, c={&z}, b={&c}, a={&b};
node * stack = &a;
you can find very useful information about liked list searching for 'linux kernel linked list':
Linux Kernel Linked List Explained
How does the kernel implements Linked Lists?
I working now in my own design of 'intrusive node' general purpose containers using c++ templates, perhaps this question might seem interesting.
node n, m;
*n = &m;
is not legal code, perhaps you mean
node n, m;
n.next = &m;
but normally this would be done with dynamic allocation
node* n = new node;
n->next = new node;
because normally you would use node to create a variable length list. Since the length of the list varies there is no way to declare the right number of variables, instead you must allocate the nodes dynamcally.
Non-duplicates:
Which STL C++ container to use for a fixed size list? (Specific use case)
std::list fixed size (See below)
Motives:
Allocation happens once (in the constructor) and deallocation happens once (in the destructor).
O(1) insertion and removal of an element anywhere in the list without needing to deal with the overhead of memory management. This isn't possible with an array-based implementation.
Is there a straightforward approach for implementing this using the standard library? Is there an implementation of something like this in Boost?
What I was first thinking when I read that was the approach to use a different allocator, i.e. one that pre-allocates a given number of elements to avoid the price of allocating. I'm not familiar with defining allocators though, but if you find out I'd be interested in the results.
Without that, here's a different approach. I saved myself the template ... stuff, but I guess you'll be able to do that yourself if you need.
typedef std::list<...> list_t;
struct fslist: private list_t
{
// reuse some parts from the baseclass
using list_t::iterator;
using list_t::const_iterator;
using list_t::begin;
using list_t::end;
using list_t::empty;
using list_t::size;
void reserve(size_t n)
{
size_t s = size();
// TODO: Do what std::vector does when reserving less than the size.
if(n < s)
return;
m_free_list.resize(n - s);
}
void push_back(element_type const& e)
{
reserve_one();
m_free_list.front() = e;
splice(end(), m_free_list, m_free_list.begin());
}
void erase(iterator it)
{
m_free_list.splice(m_free_list.begin(), *this, it);
}
private:
// make sure we have space for another element
void reserve_one()
{
if(m_free_list.empty())
throw std::bad_alloc();
}
list_t m_free_list;
};
This is incomplete, but it should get you started. Also note that splice() is not made public, because moving elements from or to a different list would change both size and capacity.
I think the simplest way to do it would be to have 2 data structures. An array/vector which is fixed sized and is used for "allocation". You simply grab an element from the array to create a node and insert it into your list. Something like this seems to meet you requirements:
struct node {
node *prev;
node *next;
int value;
};
node storage[N];
node *storage_ptr = storage;
then to create a new node:
if(node == &[storage + N]) {
/* out of space */
}
node *new_node = *storage_ptr++;
// insert new_node into linked list
This is fixed size, allocated all at once, and when storage goes out of scope, the nodes will be destroyed with it.
As for efficiently removing items from the list, it is doable, but slightly more complex. I would have a secondary linked list for "removed" nodes. When you remove a node from the main list, insert it at the end/beginning of the "deleted" list.
When allocating, check the deleted list first before going to the storage array. If it's NULL use storage, otherwise, pluck it off the list.
I ended up writing a template for this called rigid_list.
It's far from complete but it's a start:
https://github.com/eltomito/rigid_list
(motivated by Ulrich Eckhardt's answer)