Much is already answered in What's the difference between a simply-chained and a double-chained list?
Then the linked list is the same as the linked list.
The operation of the linked list is through independent nodes where the element has the element. Each element has at least one pointer indicating where the next node is. In the double-chained list has a pointer indicating the previous node. Precisely because of this, you only know where each node is if you know where the previous one or the next one is, it can only be accessed sequentially. But because we are independent, it is easy to put what you want where you want in the middle of the list.
Utility
It is useful when you need to manipulate your elements internally, ie you need to include and / or remove items in the middle of the list simply. But you have to do this very often, if it is low, it does not usually compensate (there is always an exception). Its main feature is to be O (1) for these operations. But it has O (N) for access which is the most used operation in most situations. So it's very little used.
It has the advantage of having its elements scattered, so it is easy to manipulate the list, but it has the problem of not being a contiguous sequence, so it can not access randomly, to get the element needs to do a sequential search. This still has the problem that it is not cache friendly and the processor may have to work harder to access the elements.
In fact, in most cases where there is a need for internal manipulation of the list, it is more interesting to use a binary tree that allows you to insert and remove elements in O (logN) and access the elements in O (logN). The complexity O (logN) is very close to O (1). So today it is a very little used structure, are rare the problem where you need to manipulate internally and access only needs to be sequential. In some cases
Radix may be more useful .
A common mistake is to think that insertion and removal can occur at O (1) at all times. The operation alone can always occur in O (1), but you must be on the node you want to insert or remove, otherwise you will have an additional O (N) until you reach it.
Check out Big O . Remembering that these measures are always the worst case. In the linked list the average case is O (N / 2) and the best case O (1), if it is the first (last) item.
Examples
It is very common for languages to have a linked list implementation in their default library. In C # you usually do not need to make one, it already exists at LinkedList
/ a> ( see the source code ) that caters well almost all situations. I see only one reason why someone does it on their own if you are studying the subject, if you need something very specific (very rare) or if you think that the cost of the list has two pointers is too high to use it, then a list simply linked can be more useful (rare).
There is still circular chained list , but it is very rare to need it. It has no beginning or end, when it comes to an end, it already points to the beginning. This wiki link has a more detailed description of the whole thing.
A practical example is filesystem (having nothing to do with RAM ) and virtual memory management .
A simple and naive implementation, and without being DRY, there are a lot of methods that may be useful:
using static System.Console;
public class Node<T> {
public T Value { get; set; }
public Node<T> Next { get; set; }
}
public class LinkedList<T> {
private Node<T> head = null;
public Node<T> Add(T value) {
var node = new Node<T> {Value = value};
if (head == null) {
head = node;
} else {
var current = head;
while (current.Next != null) {
current = current.Next;
}
current.Next = node;
}
return node;
}
public T Remove(Node<T> node) {
if (head == null)
return node.Value;
if (head == node) {
head = head.Next;
node.Next = null;
return node.Value;
}
var current = head;
while (current.Next != null) {
if (current.Next == node) {
current.Next = node.Next;
return node.Value;
}
current = current.Next;
}
return node.Value;
}
public void Print() {
var current = head;
while (current != null) {
WriteLine(current.Value);
current = current.Next;
}
}
}
public class Program {
public static void Main(string[] args) {
var ll = new LinkedList<int>();
var node1 = ll.Add(1);
var node2 = ll.Add(2);
var node3 = ll.Add(3);
var node4 = ll.Add(4);
var node5 = ll.Add(5);
ll.Print();
WriteLine();
ll.Remove(node3);
ll.Print();
}
}
See running on dotNetFiddle and on CodingGround .