can we construct a binary tree with singly linked list - data-structures

I have googled a lot and none of them showed how to create a binary tree with singly linked list.
Is it even possible to create one ?! I remember that I Have read somewhere that Binary trees can be created using singly linked list.

You can represent a binary tree as an array. If the only direction you want to go in your tree is root-to-leaf, then you could, in theory, use a singly linked list instead of the array.
This would result, however, in a huge performance loss as you will have to go pointer chasing instead of just jumping directly to the next node, as you do in an array.
I find it hard to think of a scenario where you would actually do that, but its possible in principle.

Related

Why LRU caches use doubly link list and not singly link list?

I have been trying to understand why LRU caches use doubly link list and not singly link list?
If i go by the time complexities they both have same for insertion , updation and deletion.
Here is the Cheat sheet
Is it because the two ways pointers in DLL is used for easier move of nodes to rear or front ??
The idea behind LRU cache implementation using list (DLL/SLL) is to move the recently used page(node) to the front.
This involves a lot of shifting, say the node is in the middle of the list (DLL/SLL), you'd have to remove the node, rearrange the next pointer of the previous node.
Now in this case, if we use Singly Linked List we'd have to maintain the previous node of the most recently accessed node.
This operation is not necessary if we use Doubly Linked List as it already maintains the previous and next pointer.
The catch here is accessing that latest node, for which we use a hashtable giving us access to that node in O(1).
To remove a targeted node from a linked list, you need to modify the other nodes that point to it.
In a doubly-linked list, the targeted node has pointers to these other nodes, so it's easy to find them.
In a single-linked list, the targeted node does not have a pointer to the other node that points to it. You still need to modify that node, though, so you'd have to search for it.

Is doubly linked list a non linear data structure or linear data structure?

A linear data structure traverses the data elements sequentially, in which only one data element can directly be reached. Ex: Arrays, Linked Lists.
But in doubly linked list we can reach two data elements using previous pointer and next pointer.
So can we say that doubly linked list is a non linear data structure?
Correct me if I am wrong.
Thank you.
Non-linear data structures are those data-structure in which the elements appear in a non-linear fashion,which requires two or more than two-dimensional representation . The elements may OR mayn't(mostly) be stored in contiguous memory locations,rather in any order/non-linearly as if you have skipped the elements in between. Accessing the elements are also done in an out-of-order pattern.
Example :- A Tree, here one may iterate from root to right child,to its right child,... and so on---thereby skipping all the left nodes.
But, in doubly linked list, you have to move sequentially(linearly) only, to move forward(using forward pointer) or backward(using previous pointer).
You can't jump from any element in the list to any distant element without traversing the intermediary elements.
Hence, doubly-linked list is a linear data structure. In a linear data structure, the elements are arranged in a linear fashion(that is,one-dimensional representation).
You are wrong; 2 justifications:
While you can get to 2 elements from any node, one of them was the one you used to get to this node, so you can only get to one new node from each.
It is still linear in that it has to be traversed sequentially, or in a line.
It is still sequential: you need to go over some elements in the list to get to a particular element, compared to an array where you can randomly access each element.
However, you can go linearly forwards or backwards, which may optimize the search.
linked list is basically a linear data Structure because it stores data in a linear fashion. A linear data Structure is what which stores data in a linear format and the traversing is in sequential manner and not in zigzag way.
It depends on where you intend to apply linked lists. If you based it on storage, a linked list is considered non-linear. On the other hand, if you based it on access strategies, then a linked list is considered linear.

Why convert BST to DLL?

conversion of Binary Search Tree to Doubly Linked List.
What is real world application or significance of this conversion?
Probably, the interviewer was trying to see if you understood what a BST and a linked list are, and also if you understood that if you do an inorder traversal of the BST, you'll get a list of the items in order. This exercise is a pretty good test of your understanding of BST traversal and linked list construction.
Building a linked list from a BST does have real-world use. For example, if you have a BST and you want to store it to disk or send it across the wire, it's easier to store or send as an ordered list of nodes. So you have to create that ordered list from the BST. In a language like C that doesn't have a dynamic list structure (like a C++ vector or a C# List<T> or a Java ArrayList), then the linked list is the tool of choice for building an arbitrarily-sized list.
Come to think of it, you could do this in-place. That is, you wouldn't need any extra memory except for the recursion stack. That would be very useful if you're working with a very large tree in a memory constrained environment such as an embedded system.
So, yes, there are real world uses for that technique.

Using mergesort for list

Mergesort can be done in-place for list;unlike an array.
However,I have not found a reference yet which explains how this is achieved.
Any pointer is appreciated.
It actually is possible, though not straightforward, to implement an in-place merge sort for arrays. With linked lists the problem becomes quite simple. Each node in a linked list just has a value and a pointer to the next node. It is quite simple to break a linked list in half. Just traverse to the middle node, take its successor as the head of your second list and then set successor to null.
The merge step works just like you would expect. Don't make any new nodes, just relink the nodes from your two lists.

When is doubly linked list more efficient than singly linked list?

In an interview today I got asked the question.
Apart from answering reversing the list and both forward and backward traversal there was something "fundamental" in it that the interviewer kept stressing. I gave up and of course after interview did a bit of research. It seems that insertion and deletion are more efficient in doubly linked list than singly linked list. I am not quite sure how it can be more efficient for a doubly linked list since it is obvious that more references are required to change.
Can anybody explain the secret behind? I honestly did a quite a bit of research and failed to understand with my main trouble being the fact that a O(n) searching is still needed for the double linked list.
Insertion is clearly less work in a singly-linked list, as long as you are content to always insert at the head or after some known element. (That is, you cannot insert before a known element, but see below.)
Deletion, on the other hand, is trickier because you need to know the element before the element to be deleted.
One way of doing this is to make the delete API work with the predecessor of the element to be deleted. This mirrors the insert API, which takes the element which will be the predecessor of the new element, but it's not very convenient and it's hard to document. It's usually possible, though. Generally speaking, you arrive at an element in a list by traversing the list.
Of course, you could just search the list from the beginning to find the element to be deleted, so that you know what its predecessor was. That assumes that the delete API includes the head of the list, which is also inconvenient. Also, the search is stupidly slow.
The way that hardly anyone uses, but which is actually pretty effective, is to define a singly-linked list iterator to be the pointer to the element preceding the current target of the iterator. This is simple, only one indirection slower than using a pointer directly to the element, and makes both insertion and deletion fast. The downside is that deleting an element may invalidate other iterators to list elements, which is annoying. (It doesn't invalidate the iterator to the element being deleted, which is nice for traversals which delete some elements, but that's not much compensation.)
If deletion is not important, perhaps because the datastructures are immutable, singly-linked lists offer another really useful property: they allow structure-sharing. A singly-linked list can happily be the tail of multiple heads, something which is impossible for a doubly-linked list. For this reason, singly-linked lists have traditionally been the simple datastructure of choice for functional languages.
Here is some code that made it clearer to me... Having:
class Node{
Node next;
Node prev;
}
DELETE a node in a SINGLE LINKED LIST -O(n)-
You don't know which is the preceeding node so you have to traverse the list until you find it:
deleteNode(Node node){
prevNode = tmpNode;
tmpNode = prevNode.next;
while (tmpNode != null) {
if (tmpNode == node) {
prevNode.next = tmpNode.next;
}
prevNode = tmpNode;
tmpNode = prevNode.next;
}
}
DELETE a node in a DOUBLE LINKED LIST -O(1)-
You can simply update the links like this:
deleteNode(Node node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
Here are my thoughts on Doubly-Linked List:
You have ready access\insert on both ends.
it can work as a Queue and a Stack at the same time.
Node deletion requires no additional pointers.
You can apply Hill-Climb traversal since you already have access on both ends.
If you are storing Numerical values, and your list is sorted, you can keep a pointer/variable for median, then Search operation can be highly optimal using Statistical approach.
If you are going to delete an element in a linked list, you will need to link the previous element to the next element. With a doubly linked list you have ready access to both elements because you have links to both of them.
This assumes that you already have a pointer to the element you need to delete and there is no searching involved.
'Apart from answering reversing the list and both forward and backward traversal there was something "fundamental"'.
Nobody seem to have mentioned: in a doubly linked list it is possible to reinsert a deleted element just by having a pointer to the deleted element. See Knuth's Dancing Links paper. I think that's pretty fundamental.
Because doubly linked lists have immediate access to both the front and end
of the list, they can insert data on either side at O(1) as well as delete data on either side at O(1). Because doubly linked lists can insert data at the end in O(1) time and delete data from the front in O(1) time, they make the perfect underlying data structure for a queue. Queeus are lists of items
in which data can only be inserted at the end and removed from the beginning.
queues are an example of an abstract data type, and
that we are able to use an array to implement them under the hood.
Now, since queues insert at the end and delete from the beginning, arrays
are only so good as the underlying data structure. While arrays are O(1) for
insertions at the end, they’re O(N) for deleting from the beginning.
A doubly linked list, on the other hand, is O(1) for both inserting at the end
and for deleting from the beginning. That’s what makes it a perfect fit for
serving as the queue’s underlying data structure.
The doubly linked list is used in LRU cache design since we need to remove the least recently items frequently. The deletion operation is faster. To delete the least recently used item, we just delete if from end, to a new item to add cache, we just append a new node to the beginning of the list
Doubly Linked List is used in navigation systems where front and back navigation is required. It is also used by the browser to implement backward and forward navigation of visited web pages that is a back and forward button.
Singly Linked List vs Doubly Linked List vs Dynamic Arrays:
When comparing the three main data structures, Doubly Linked Lists are most efficient in all major tasks and operations when looking at time complexity. For Doubly Linked Lists, it operates at constant time for all operations except only access by index, where it operated at linear time (n) as it needs to iterate through each node to get to the required index. When it comes to Insert, Remove, First, Last, Concatenation and Count, Doubly Linked list operates at constant time where Dynamic Arrays operate at linear time (n).
In terms of space complexity, Dynamic Arrays stores only elements therefore constant time complexity, singly linked lists stores the successor of each element therefore linear space complexity (n), and worst of all doubly linked list stores the predecessor and successor of each element and therefore also linear space complexity but (2*n).
Unless you have extremely limited resources / space then perhaps either Dynamic arrays or Singly linked lists are better, however, nowadays, space and resources are more and more abundant and so doubly linked lists are far better with the cost of more space.
Doubly Linked list is more effective than the Singly linked list when the location of the element to be deleted is given. Because it is required to operate on "4" pointers only & "2" when the element to be deleted is at the first node or at the last node.
struct Node {
int Value;
struct Node *Fwd;
struct Node *Bwd;
);
Only the below line of code will be enough to delete the element, if the element to be deleted is not in the first or last node.
X->Bwd->Fwd = X->Fwd; X->Fwd->Bwd = X->Bwd;

Resources