What is the best data structure for removing an element from the middle? - c++

The data stucture must be like a stack. Only with one difference. I want to pop from any index not only last. When I have popped element n, the elements with indexes N > n must swap to N-1. Any ideas?
P.S.
Pushing element n into the last index of the stack.
Then popping it out.
Then deleting stack[n]
is a bad idea.

I think you're looking for a linked list.

A linked list (std::list) will allow you to remove an element from the middle with O(1) complexity and automatically "pull" up the elements after it. You can use a linked list like a stack by using push_front. However you need to be aware that accessing an element in a linked list is O(n) as you would need to start at the head of the list and then walk along the links from one element to the next until you have arrived at element n (so there is no O(1) indexing)
Basically you would need to
Create an iterator
advance it to position n
Get the element from the iterator
erase the element the iterator is currently pointing to
Some example code can be found here.

You need to implement a linked list, but unlike an array, the order in a linked list is determined by a pointer in each object. So, you cannot use indices to access the elements.

Related

Good sources to understand Containers

I'm studying containers and their different performances.
When , for a vector, I read something like
"inserting elements other than the back is slow"
but for a list:
"fast insert/delete at any point"
My questions are:
How a vector is different from a list in such a way that the two sentences above are true?
How its a vector built differently from a list?
Is because they store their elements in different memory parts?
I was searching some sources to better understand these concepts.
All examples will be linked to C++ language as I believe it is perfectly described there
Vectors
Vectors are the same as dynamic arrays with the ability to resize themselves
automatically when an element is inserted or deleted, with their
storage being handled automatically by the container. Vector elements
are placed in contiguous storage so that they can be accessed and
traversed using iterators. In vectors, data is inserted at the end.
Inserting at the end takes differential time, as sometimes there may
be a need of extending the array. Removing the last element takes only
constant time because no resizing happens. Inserting and erasing at
the beginning or in the middle is linear in time.
Vector is the dynamic array, but which can manage the memory allocated to itself. This means that you can create arrays whose length is set at runtime without using the new and delete operators (explicitly specifying the allocation and deallocation of memory).
Lists
Lists are sequence containers that allow non-contiguous memory
allocation. As compared to vector, the list has slow traversal, but once a
position has been found, insertion and deletion are quick. Normally,
when we say a List, we talk about a doubly linked list. For implementing
a singly linked list, we use a forward list.
There are 2 types of lists:
Double linked list where each element has an address of [next]
and [previous], to access first or last element you could you a specific function (e.g. in C++ front() or back() on the list - listName.front() will return you the 1st(0) element in your list), head.previous point to NULL and the tail.next point to NULL;
Single linked list where each element only has the link(knows)
about the [next] element, and the last element in this list points
to NULL.
Now let's get back to your question:
how a vector is different from a list in such a way
that the two sentences above are true? How is a vector built
differently from a list? Is it because they store their elements in
different memory parts? I was searching some sources to better
understand these concepts.
As I have mentioned there are 2 types of lists (single linked and double liked), they are good when you are going to have:
many insertion/deletion everywhere except the end of a list;
You could use vector in case you are planning to:
frequently access insert/delete elements at the end of a list;
access elements at the random position (as you could use [N] to access the element at any point, where the N is the index/position of an element.
Whereas in the List you would need to use iterators to access the element at the position/index N.
So vector is a dynamic array and they tend to perform faster when you are accessing it (since there is no additional wrapper over it, and you directly access a point in memory by the pointer).
The list is a sequence container (so this one has a wrapper over some base language functionality) that sacrifices some point in favor of additional simplicity of insertion and deletion by providing a user with some useful methods to work with its elements.
And to resolve you question, we could conclude the following:
Vector
inserting elements other than the back is slow
List
fast insert/delete at any point
This can be judged by the structure they have what they are.
Insertion is swift in List because it is a linked list and this
means what? Exactly, This means that the only change is to be taken
to achieve it is to change the pointer of the [previous ] and the
[next] item, and we are done!
Whereas in Vector it would take waaaay more time to insert an element anywhere other than at the end. This could be proven by the array concept. If you have an array of one million elements and you want to replace/delete/insert the element at the very beginning of the array it would need to change the position of each element that is coming after the altered element.
List vs Vector Image:
images were taken from this sources:
singly linked list
double linked list
double linked list 2nd image
vector
Also, try having a look here vector-vs-list-in-stl. Their comparison is well described there. + look through the-c-standard-template-library-stl, by going to the "Containers" section and checking the description and its methods.

What is the purpose of sorting a linked list?

I am wondering what is the purpose of sorting a linked list. Because if you need to find an element in an unsorted linked list and a sorted linked list, you have to do O(n).
Please forgive if my question is stupid
The purpose of sorting isn't always to search in logarithmic time. There are lots of other applications of sorted data obviously.
Suppose, you have to de-duplicate(remove the duplicate elements) from a large linked list and you don't have enough space to load the list items into hashtable as the list is very big. In this case, you can sort the list and remove consecutive elements if they are same and thus de-duplicate the list.
If you want to insert an element into it's appropriate position in a sorted container, sorted linked list is very handy which will guarantee linear time and constant space complexity. But for array, you need to use a temporary array and move all the elements afterwards one by one. Infact LRU cache is a doubly-linked list under the hood and keep sorted based on the recent hit on items. Newly used item and old item which is recently being accessed again, are inserted in front to keep the already sorted list sorted. If an array like structure would be used here, LRU cache can't offer of constant complexity
This is just some classic applications. You can find a lot of other applications.
Let us think a linked list is used to implement a priority queue. We can add elements of different priorities at random, but we want to process the elements of the queue according to priority, it would be useful to maintain a sorted linked list so that the top priority items appear at the beginning, and removing them from the queue is an easy operation. This not exactly sorting the list, but as and when an item is inserted, it would be placed in it's correct position based on the priority. This is similar to insertion sort of an array.

Run-times of sorted linked list

What is the run time to find an element, insert an element, and remove an element in a sorted linked list?
I believe that they're all O(n) since you have to go through each link regardless. Am I right?
Yes you are right. Think about it, regardless of whether or not you know the order of the nodes, the only way to actually access any node is to go through the node before it. That means for N nodes you have to go through N nodes making the operation O(N).

Time Complexity in singly link list

I am studying data-structure: singly link list.
The website says singly linked list has a insertion and deletion time complexity of O(1). Am I missing something?
website link
I do this in C++, and I only have a root pointer. If I want to insert at the end, then I have to travel all the way to the back, which means O(n).
The explanation for this is, that the big O notation in the linked table refers to the function implementation itself, not including the list traversal to find the previous reference node in the list.
If you follow the link to the wikipedia article of the Singly-LinkedList implementation it becomes more clear:
function insertAfter(Node node, Node newNode)
function removeAfter(Node node)
The above function signatures already take the predecessor node as argument (same for the other variants implicitly).
Finding the predecessor is a different operation and may be O(n) or other time complexity.
You missed the interface at two places:
std::list::insert()/std:list::erase() need an iterator to the element where to insert or erase. This means you have no search but only alter two pointers in elements in the list, which is constant complexity.
Inserting at the end of a list can be done via push_back. The standard requires this to be also O(1). Which means, if you have a std::list, it will store first and last element.
EDIT: Sorry, you meet std::forward_list. Point 1 holds also for this even if the names are insert_after and erase_after. Points 2 not, you have to iterate to the end of the list.
I do this in C++, and I only have a root pointer. If I want to insert at the end, then I have to travel all the way to the back, which means O(n).
That's two operations, you first search O(n) the list for given position, then insert O(1) element into the list.
In a single linked list, the operation of insertion consists of:
alternating pointer of previous element
wrapping object into data structure and setting its pointer to next element
Both are invariant to list size.
On the other hand, take for example a heap structure. Insertion of each element requires O(log(n)) operations for it to retain its structure. Tree structures have similar mechanisms that will be run upon insertion and depend on current tree size.
Here it is considered that you already have the node after which you need to add a new element.
In that case for a singly-linked-list insertion time complexity becomes O(1).
The fact is that, unlike an array, we don’t need to shift the elements of a singly-linked list while doing an insertion. Therefore, the insertion time complexity of a singly-linked list is O(1).
Imagine that you have a Python list filled with integer numbers...
my_list = [9, 8, 4, 5, 6]
... and you want to insert the number 3 right after the element 8.
my_list.insert(2, 3)
The printed result will be:
[9, 8, 3, 4, 5, 6]
When you do an insertion to my_list, the other elements after the element 3 are all shifted towards the right, so their indexes are changed. As a result, the time complexity to insert an element at a given index is O(n).
However, in singly-linked lists, there are no array elements, but chained nodes and node values.
Image source: LeetCode
As the above image shows, the prev node holds the reference of the next node. As #πάντα ῥεῖ stated, "function signatures already take the predecessor node as argument". You can find the previous node in O(n) time, but while inserting a new node, you just need to change the addresses of connected nodes and that is O(1) time complexity.

what is the difference between linked list and array when search through them?

I understand that array's value can be accessed directly by their position and linked list have to go through them one by one but have no idea of how to explain the difference in terms of their overhead and storage when the search is happening.
( I am think more in terms of does the previous node need to temporary store somewhere while try to access the next node any additional storage or overhead on the system part when go through them? and same when search through an array)
Can anyone give me a detail of what happen when search in each structure? or simply point to a right direction
An array is a vectorial variable of a fixed size.
A Linked List has no specified size: each element of the list contains a pointer to the next element. That's why you need to iterate through it sequentially. The advantage here, is that the structure shall not be allocated in a sequential block of memory, and doesn't need to resize if you add more elements in it.
Also in an array, if you remove an element, you need to shift all previous elements. If you insert an element in the middle of an array, you need to shift elements to make space for the new one. In lists you just update the pointers:
On the other side, array can be accessed randomly and don't need sequential access: so they are faster to search for objects, to sort, etc.
Having random access to a list element allows you to implement search algorithms such as a binary search, which would be impractical using a linked list.