Can I delete array element by element? - c++

I'm trying to create custom list. This is the node structure:
struct Node {
ListNode* prev;
ListNode* next;
void* data;
};
One of constructors creates list from array. So I decided to allocate nodes in consecutive part of memory to make algorithm a little bit faster.
auto elements = new Node[size];
elements[0] = ...
elements[size - 1] = ...
for (int i = 1; i + 1 < size; i++) {
elements[i].data = array[i];
elements[i].prev = &elements[i - 1];
elements[i].next = &elements[i + 1];
}
head = &elements[0];
tail = &elements[size - 1];
After that I can add new elements:
Node* tmp = new Node;
tmp->prev = tail;
tmp->data = data;
tail = tmp;
Also I can change next and prev.
So I can't distinguish elements(is this element part of array or have been allocated later using new) and in destructor I have to delete elements using delete instead of delete[].
Node* curNode = head;
for (int i = 0; i < size; i++) {
Node* tmp = curNode.next;
delete curNode;
curNode = tmp;
}
This code doesn't delete elements which have been allocated in array(according to Valgrind).
How can I allocate nodes in one array(to decrease number of cache misses) and then successfully delete them element by element?

What you are trying to do is the most hacky implementation of linked list you can possibly think of. For all real life purpose you should stick with STL and it looks like std::vector does what you want. That being said, if you are trying to implement your own linked list to learn how it works, let me start by saying that you are already doing it wrong.
By definition linked list is made out of Nodes where each Node points to the next one and can also point to previous. Physical order of individual nodes in memory plays no role and is irrelevant from functionality point of view. There is potential performance gain related do cache hits if you have bunch of consecutive Nodes in the same page, but it is not something you should be aiming at when implementing linked list. If your goal is to have top tier performance, then pure array list will always beat any linked list implementation you can come up with. And std::vector is already what you should be using 99% of the time.
If you already implement a function that takes collection of elements and build Nodes out of them, you somewhat enforce OS to gets you chunks of memory for Nodes in kind of contiguous fashion. It's not a strong guarantee, but I would consider it good enough.
You can't release individual elements that belongs to a chunk of memory created with new[]. If you want to stick to array as your underlying storage for Nodes you have two options, as already mentioned in comments.
Option 1) Allocate single array for whole list and use indexes as your next and previous pointers in nodes. Note that it would require you to somehow handle situation when your list will be asked to hold more elements than your array can handle. Most likely allocating more arrays or allocating bigger one and copying everything which will bring you to array list with fancy ordering.
Option 2) Add dedicated memory manager that will be allocating chunks of memory in form of arrays and will handle individual entries, which is basically implementing your own memory allocator.

Related

How to clean up a Minimum Spanning Tree

I am working on a project that uses an MST using the prim algorithm:
After completing my code and testing I was trying to clean and deallocate my calculated prim function, but I complicated my code with a pointer class to a different pointer.
Here my code with my logic to deallocate the code:
Adj_Node *curr_element;
Adj_Node *next_element;
for (int i = 0; i < n_nodes; i++)
{
curr_element = array_elements[i].head_list;
while (curr_element != nullptr)
{
std::cout << curr_element.dest_node << "\t";
next_element = curr_element[i].next_node;
delete curr_element;
curr_element = next_element;
}
}
Here some variables from my classes:
Adj_List * array_elements; Adj_Node *head_list; Adj_Node *next_node;
Basically, array_elements is an array of head lists, and the head list is an array of the next node.
I followed this tutorial for the Adj_List *: https://www.geeksforgeeks.org/prims-mst-for-adjacency-list-representation-greedy-algo-6/
If you can help me with how to deallocate this element which is the same as the element of the tutorial I will appreciate it (basically a function clean for the given tutorial). Thank you for your help in advance.
Edith:
Thanks for answering my question. I think I forgot to mention I am using classes instead of structures from the tutorial code into different files like adj_node adj_list. The problem is that I try to deallocate two pointers, say (0,1);(1;0), and when I run the code it scapes from the execution program. I am unsure of the reason.
This is what I have for adding, so maybe there is something there that can clarify how I allocate memory
Adj_Node *new_node = new Adj_Node(v, w);
// Store head_list of array_heap elements into head_list
new_node->next_node = array_elements[u].head_list;
// And store array_heap to node
array_elements[u].head_list = new_node;
// Since graph is undirected, add an edge from dest to src also
new_node = new Adj_Node(u, w);
new_node->next_node = array_elements[v].head_list;
array_elements[v].head_list = new_node;
I think the problem is that I create a linkedlist array_elements[v].headlist->array_elements[v].headlist-array_elements[v], but I am unsure. Happy to know what you think.
When the nodes form a connected graph, there will be nodes having multiple references to them. If you walk overlapping paths across the graph "deleting as you go" you will cause multiple deletions to be attempted on the nodes, which will cause a segmentation fault (when attempting to delete a node that is already deleted).
You have a few options:
Maintain a node list whilst building the graph - this has ownership of the nodes and is responsible for deleting them at cleanup. A std::vector can be a good candidate for this. (This option would be my recommendation)
Walk the nodes at cleanup and build a list, avoiding duplicates. When all paths walked, delete everything in the list.
Use smart pointers (std::shared_ptr) for creating the nodes and copy them in the nodes for referencing the "adjacent-node". The references to them can be cleared when walking the paths at cleanup. The nodes are not deleted until all references are reset.
For more information on dangling references and smart pointers, take a look at:
this paper: http://umich.edu/~eecs381/handouts/C++11_smart_ptrs.pdf
this article: https://www.acodersjourney.com/top-10-dumb-mistakes-avoid-c-11-smart-pointers/
Scott Meyer's book: https://www.amazon.co.uk/Effective-Modern-Specific-Ways-Improve/dp/1491903996

C++ avoid dynamic memory allocation

Imagine I have some Node struct that contains pointers to the left and right children and some data:
struct Node {
int data;
Node *left;
Node *right;
};
Now I want to do some state space search, and naturally I want to construct the graph as I go. So I will have a kind of loop that will have to create Nodes and keep them around. Something like:
Node *curNode = ... ; // starting node
while (!done) {
// ...
curNode->left = new Node();
curNode->right = new Node();
// ..
// Go left (for example)
curNode = curNode->left;
}
The problem is that I have to dynamically allocate node on each iteration, which is slow. So the question is: how can I have pointers to some memory but not by allocating it one by one?
The first solution I thought of is to have a std::vector<Node> that will contain all the allocated nodes. The problem is that when we push_back elements, all references might be invalidated, so all my left/right pointers will be garbage.
The second solution is to allocate a big chunk of memory upfront, and then we just grab the next available pointer when we want to create a Node. To avoid references invalidation, we just have to create a linked list of big chunks of memory when we exceed the capacity of the current chunk so every given pointer stays valid. I think that std::deque behaves like this, but it's not explicitly created for this.
Another solution would be to store vector indices instead of pointers but this is not a solution because a Node doesn't want to be associated with any container, it wants the pointer directly.
So what is the good solution here, that would avoid having to allocated new nodes on each iteration?
You can use std::deque<Node> and it will do memory management for you creating elements by groups and no invalidating pointers if you do not delete elements in middle. Though if you want to have more precise control on how many elements in a group you can quite simply create something like that:
class NodePool {
constexpr size_t blockSize = 512;
using Block = std::array<Node,blockSize>;
using Pool = std::list<Block>;
size_t allocated = blockSize;
Pool pool;
public:
Node *allocate()
{
if( allocated == blockSize ) {
pool.emplace_back();
allocated = 0;
}
return &( pool.back()[ allocated++ ] );
}
};
I did not try to compile it, but it should be enough to exress the idea. Here changing blockSize you can fine tune performance of your program. Though you should be aware than Node objects will be fully constructed by groups (unlike hoiw std::deque would do it). As much as I am aware there is no way to create raw memory for Node objects which is standard comformant.

How to manage an array of pointers to a struct

I have the following struct:
struct Item
{
Item* nextPtr;
int intKey;
int intValueLength;
};
Based of such a struct I need to maintain several linked lists, which means I need to keep track of one head pointer for each one. I have thought about using an array (HEADS) which will contain a head pointer for each list. The number of lists is variable and will be calculated at run time so I am defining the array dynamically as follows:
int t = 10;
Item* HEADS = new Item[t];
Firstly, I need to initialize each head pointer to NULL because the linked lists are empty when the program runs. How do I do this initialization?
for (int i = 0; i <= t - 1; i++)
// Initialize each element of HEADS to NULL.
And, of course, I will also need to update each element of HEADS with the proper pointer to a linked list (when inserting and deleting items) and also to get the value of each head pointer to display the elements of each list.
I have seen other posts similar to this one in the forum but I am still confused, that is why I am asking my specific situation.
Is this a good approach?
I will very much appreciate your advice.
Respectfully,
Jorge Maldonado
In C++ the common way to write the initialization for loop would be
for (int i = 0; i < t ; i++)
HEADS[i] = NULL;
Or you could write
for (int i = 0 ; i < t ; HEADS[i++] = NULL);
which is slightly more compact.
As to the question of whether an array of pointers is a good idea or not - if you're going to have a variable number of lists, perhaps you should use a linked list of pointers to other linked lists.
I do wonder about your data structure, though. In it you have a pointer to the next element in the list, a key value, and a the length of the value, but you don't appear to have a reference to a value - unless the "key" is really the value, in which case you have mixed terminology - that is, you refer to something in one place as a "key" and in another as a "value. Perhaps you need a pointer to a "value"? But I don't know what you're trying to do here so I just thought I'd note that issue.
Best of luck.
Good approach? That's a very, very dependent on things. Good for a student starting to learn C, maybe. Good for a real C++ programmer? Absolutely not. If you really want to create a linked-list, you should make a class that encompasses each element of these, and dynamically add elements. This is how std::list, for example, works. (std::list is doubly-linked list, and way more complicated).
Here's a sample class of how this should look like (off the top of my head; haven't compiled it, but should work):
struct LinkedList
{
Item* list;
int size = 0;
LinkedList() //constructor of this class/struct, it's the function that will be called once you create an object of LinkedList
{
list = nullptr; //don't use NULL, it's deprecated (this is for C++11, or change it back to NULL if you insist on using C++98)
}
addItem(const int& key)
{
Item item; //construct a new item
item.intKey = key; //fill the value in the item
Item* newList = new Item[size+1]; //create the new list with one more element
for(int i = 0; i < size; i++) //copy the old list to the new list
{
newList[i] = list[i]; //copy element by element
}
list[size] = item; //fill in the new item
if(size > 0)
{
list[size - 1].nextPtr = &list[size]; //assign "next pointer" for previous element
}
size = size+1; //increase the size of the list
}
~linkedList()
{
if(list != nullptr)
{
delete[] list;
}
}
}
Now this is better, but it's still far from optimal. However, this is how C++ should be used. You create objects and deal with them. What you did above is more like C, not C++.
To my code, you have to call:
LinkedList myList;
myList.addItem(55);
There are many things to do here to make this optimal. I'll mention a few:
In my code, every time you add an item, a new array is allocated. This is bad! std::vector solves this problem by allocating a bigger size than needed (for example, you add 1 item, it reserves 10, but uses only 1, and doesn't tell you that). Once you need more than 10, say 11, it reserves 20, maybe. This optimizes performance.
Try to read my code and understand it. You'll learn so much. Ask questions; I'll try to answer. And my recommendation is: get a C++ book, and start reading.

Linked Lists with vectors

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.

How to implement a compact linked list with array?

Here is the question of exercise CLRS 10.3-4 I am trying to solve
It is often desirable to keep all elements of a doubly linked list compact in storage,
using, for example, the first m index locations in the multiple-array representation.
(This is the case in a paged, virtual-memory computing environment.) Explain how to implement the procedures ALLOCATE OBJECT and FREE OBJECT so that the representation is compact. Assume that there are no pointers to elements of the linked list outside the list itself. (Hint: Use the array implementation of a stack.)
Here is my soln so far
int free;
int allocate()
{
if(free == n+1)
return 0;
int tmp = free;
free = next[free];
return tmp;
}
int deallocate(int pos)
{
for(;pos[next]!=free;pos[next])
{
next[pos] = next[next[pos]];
prev[pos] = prev[next[pos]];
key[pos] = key[next[pos]];
}
int tmp = free;
free = pos;
next[free] = tmp;
}
Now , The problem is , If this is the case , We don't need linked list. If deletion is O(n) we can implement it using normal array. Secondly I have not used the array implementation of stack too . So where is the catch? How should I start?
You don't have to shrink the list right away. Simply leave a hole and link that hole to your free list. Once you've allocated the memory, it's yours. So let's say your page size is 1K. Your initial allocated list size would then be 1K, even if the list is empty. Now you can add and remove items very effectively.
Then introduce another method to pack your list, i.e. remove all holes. Keep in mind that after calling the pack-method, all 'references' become invalid.