Run-times of sorted linked list - c++

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).

Related

why Run-time for add-before for doubly-linked lists is O(1)?

In data structures, we say pushing an element before a node in singly-linked lists are O(n) operation! since there is no backward pointers, we have to walk all the way through the elements to get to the key we are going to add before the new element. Therefore, it has a linear run time.
Then, when we introduce doubly-linked lists, we say the problem is resolved and now since we have pointers in both directions pushing before becomes a constant time operation O(1).
I understand the logic but still, something is confusing to me! Since we DO NOT have constant time access to the elements of the list, for finding the element we want to add before, we have to walk through the previous element to get there! that is true that in the doubly-linked list it is now faster to implement the add-before command, but still, the action of finding the interested key is O(n)! then why we say with the doubly-linked list the operation of add before becomes O(1)?
Thanks,
In C++, the std::list::insert() function takes an iterator to indicate where the insert should occur. That means the caller already has this iterator, and the insert operation is not doing a search and therefore runs in constant time.
The find() algorithm, however, is linear, and is the normal way to search for a list element. If you need to find+insert, the combination is O(n).
However, there is no requirement to do a search before an insert. For example, if you have a cached (valid) iterator, you can insert in front of (or delete) the element it corresponds with in constant time.

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.

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

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.

Delete duplicates from Doubly linked list

Hello
I stumbled following question
You given unsorted doubly linked list.You should find and delete duplicates from Doubly linked list.
What is the best way to do it with minimum algorithmic complexity?
Thank you.
If the space is abundance and you have to really optimize this with time, perhaps you can use a Hashset (or equivalent in C++). You read each element and push it to the hashset. If the hashset reports a duplicate, it means that there is a duplicate. You simply would delete that node.
The complexity is O(n)
Think of it as two singly linked lists instead of one doubly linked list, with one set of links going first to last and another set going last to first. You can sort the second list with a merge sort, which will be O(n log n). Now traverse the list using the first link. For each node, check if (node.back)->key==node.key and if so remove it from the list. Restore the back pointer during this traversal so that the list is properly doubly linked again.
This isn't necessarily the fastest method, but it doesn't use any extra space.
Assuming that the potential employer believes in the C++ library:
// untested O(n*log(n))
temlate <class T>
void DeDup(std::list<T>& l) {
std::set<T> s(l.begin(), l.end());
std::list<T>(s.begin(), s.end()).swap(l);
}
With minimum complexity? Simply traverse the list up to X times (where X is the number of items), starting at the head and then delete (and reassign pointers) down the list. O(n log n) (I believe) time at worse case, and really easy to code.

Is time complexity for insertion/deletion in a doubly linked list of order O(n)?

To insert/delete a node with a particular value in DLL (doubly linked list) entire list need to be traversed to find the location hence these operations should be O(n).
If that's the case then how come STL list (most likely implemented using DLL) is able to provide these operations in constant time?
Thanks everyone for making it clear to me.
Insertion and deletion at a known position is O(1). However, finding that position is O(n), unless it is the head or tail of the list.
When we talk about insertion and deletion complexity, we generally assume we already know where that's going to occur.
It's not. The STL methods take an iterator to the position where insertion is to happen, so strictly speaking, they ARE O(1), because you're giving them the position. You still have to find the position yourself in O(n) however.
Deleting an arbitrary value (rather than a node) will indeed be O(n) as it will need to find the value. Deleting a node (i.e. when you start off knowing the node) is O(1).
Inserting based on the value - e.g. inserting in a sorted list - will be O(n). If you're inserting after or before an existing known node is O(1).
Inserting to the head or tail of the list will always be O(1) - because those are just special cases of the above.