Implementing Linked List in an array - linked-list

Implementing Linked List in an array
As far as i understand:
Deletion will be done in O(1) time as we will just move front pointer,but reverse will take O(n) time. Please correct me if i am understanding it wrong.

As you mentioned delete can be done in constant time, a doubly linked list with head and tail pointers can be reversed in O(1) time by swapping head and tail pointers. Here P is the first element and last pointer is (first element + list size) mod n , this means
first element a has pointers to itself and last element
second element a has pointer to itself and the element before first element which is first element
3rd element has pointer to itself and second element
and so on , so by swapping first and last pointer you can reverse the list in O(1)

Related

DART - Why 'set' data structure is told to be unordered?

I see in dart tutorial's websites that ((A set is an unordered collection of values. We can’t get the values by their index values as they are unordered.)) but we can:
main(List<String> args) {
Set a = Set();
a.add(10);
a.add(20);
a.add(40);
a.add(50);
var p = a.elementAt(0);
print(p);
}
so what is the meaning of the unordered collection??
I see Andreas Florath's Answer too :
Why 'set' data structure is told to be unordered?
but I didn't understand.
can anyone help to understand what's the meaning of unordered?
Depending on the type of Set, it might be one that optimizes for preserving order, or it might be one that optimizes for look-up speed, or it might be one that optimizes for insertion speed. You can't get all three at once. Take a look at each of the "implementors" in the Set documentation (https://api.flutter.dev/flutter/dart-core/Set-class.html), which also says:
A HashSet is unordered, which means that its iteration order is
unspecified, LinkedHashSet iterates in the insertion order of its
elements, and a sorted set like SplayTreeSet iterates the elements in
sorted order.

Why implement an immutable list as a linked-list?

According to F#'s list documentation:
"A list in F# is an ordered, immutable series of elements of the same type"
"Lists in F# are implemented as singly linked lists"
Why not implement it contiguously in memory since it immutable and thus has a fixed size? Why ever use an F# list instead of an F# array?
They serve different purposes, for instance:
You use an Array in F# to store big amounts of data that needs to be accessed randomly with relative low overhead.
A List in F# is useful when you need to accumulate something over iterations of a recursive function. Arrays don't play well here, since they have a fixed size.
With a list, you can prepend all elements of ListM (size M) to ListN (size N) in O(M) time. Similarly, you can prepend a single Element to any list in O(1) time.

Why don't F# lists have a tail pointer

Or phrased another way, what kind of benefits do you get from having a basic, singly linked list with only a head pointer? The benefits of a tail pointer that I can see are:
O(1) list concatenation
O(1) Appending stuff to the right side of the list
Both of which are rather convenient things to have, as opposed to O(n) list concatenation (where n is the length of the left-side list?). What advantages does dropping the tail pointer have?
F#, like many other functional[-ish] languages, has a cons-list (the terminology originally comes from LISP, but the concept is the same). In F# the :: operator (or List.Cons) is used for cons'ing: note the signature is ‘a –> ‘a list –> ‘a list (see Mastering F# Lists).
Do not confuse a cons-list with an opaque Linked List implementation which contains a discrete first[/last] node - every cell in a cons-list is the start of a [different] list! That is, a "list" is simply the chain of cells that starts at a given cons-cell.
This offers some advantages when used in a functional-like manner: one is that all the "tail" cells are shared and since each cons-cell is immutable (the "data" might be mutable, but that's a different issue) there is no way to make a change to a "tail" cell and flub up all the other lists which contain said cell.
Because of this property, [new] lists can be efficiently built - that is, they do not require a copy - simply by cons'ing to the front. In addition, it is also very efficient to deconstruct a list to head :: tail - once again, no copy - which is often very useful in recursive functions.
This immutable property generally does not exist in a [standard mutable] Double Linked List implementation in that appending would add side-effects: the internal 'last' node (the type is now opaque) and one of the "tail" cells are changed. (There are immutable sequence types that allow an "effectively constant time" append/update such as immutable.Vector in Scala -- however, these are heavy-weight objects compared to a cons-list that is nothing more than a series of cells cons'ed together.)
As mentioned, there are also disadvantages a cons-list is not appropriate for all tasks - in particular, creating a new list except by cons'ing to the head is an O(n) operation, fsvo n, and for better (or worse) the list is immutable.
I would recommend creating your own version of concat to see how this operation is really done. (The article Why I love F#: Lists - The Basics covers this.)
Happy coding.
Also see related post: Why can you only prepend to lists in functional languages?
F# lists are immutable, there's no such thing as "append/concat", rather there's just creating new lists (that may reuse some suffixes of old lists). Immutability has many advantages, outside the scope of this question. (All pure languages, and most functional languages have this data structure, it is not an F#-ism.)
See also
http://diditwith.net/2008/03/03/WhyILoveFListsTheBasics.aspx
which has good picture diagrams to explain things (e.g. why consing on the front is cheaper than at the end for an immutable list).
In addition to what the others said: if you need efficient, but yet immutable data structures (which should be an idiomatic F# way), you have to consider reading Chris Okasaki, Purely Functional Data Structures. There is also a thesis available (on which the book is based).
In addition to what has been already said, the Introducing Functional Programming section on MSDN has an article about Working with Functional Lists that explains how lists work and also implements them in C#, so it may be a good way to understand how they work (and why adding reference to the last element would not allow efficient implementation of append).
If you need to append things to the end of the list, as well as to the front, then you need a different data structure. For example, Norman Ramsey posted source code for DList which has these properties here (The implementation is not idiomatic F#, but it should be easy to fix).
If you find you want a list with better performance for append operations, have a look at the QueueList in the F# PowerPack and the JoinList in the FSharpx extension libraries.
QueueList encapsulates two lists. When you prepend using the cons, it prepends an element to the first list, just as a cons-list. However, if you want to append a single element, it can be pushed to the top of the second list. When the first list runs out of elements, List.rev is run on the second list, and the two are swapped putting your list back in order and freeing the second list to append new elements.
JoinList uses a discriminated union to more efficiently append whole lists and is a bit more involved.
Both are obviously less performant for standard cons-list operations but offer better performance for other scenarios.
You can read more about these structures in the article Refactoring Pattern Matching.
As others have pointed out, an F# list could be represented by a data structure:
List<T> { T Value; List<T> Tail; }
From here, the convention is that a list goes from the List you have a reference to until Tail is null. Based on that definition, the benefits/features/limitations in the other answers come naturally.
However, your original question seems to be why the list is not defined more like:
List<T> { Node<T> Head; Node<T> Tail; }
Node<T> { T Value; Node<T> Next; }
Such a structure would allow both appending and prepending to the list without any visible effects to the a reference to the original list, since it still only sees a "window" of the now expanded list. Although this would (sometimes) allow O(1) concatenation, there are several issues such a feature would face:
The concatenation only works once. This can lead to unexpected performance behavior where one concatenation is O(1), but the next is O(n). Say for example:
listA = makeList1 ()
listB = makeList2 ()
listC = makeList3 ()
listD = listA + listB //modified Node at tail of A for O(1)
listE = listA + listC //must now make copy of A to concat with C
You could argue that the time savings for the cases where possible are worth it, but the surprise of not knowing when it will be O(1) and when O(n) are strong arguments against the feature.
All lists now take up twice as much space, even if you never plan to concatenate them.
You now have a separate List and Node type. In the current implementation, I believe F# only uses a single type like the beginning of my answer. There may be a way to do what you are suggesting with only one type, but it is not obvious to me.
The concatenation requires mutating the original "tail" node instance. While this shouldn't affect programs, it is a point of mutation, which most functional languages tend to avoid.
Or phrased another way, what kind of benefits do you get from having a basic, singly linked list with only a head pointer? The benefits of a tail pointer that I can see are:
O(1) list concatenation
O(1) Appending stuff to the right side of the list
Both of which are rather convenient things to have, as opposed to O(n) list concatenation (where n is the length of the left-side list?).
If by "tail pointer" you mean a pointer from every list to the last element in the list, that alone cannot be used to provide either of the benefits you cite. Although you could then get at the last element in the list quickly, you cannot do anything with it because it is immutable.
You could write a mutable doubly-linked list as you say but the mutability would make programs using it significantly harder to reason about because every function you call with one might change it.
As Brian said, there are purely functional catenable lists. However, they are many times slower at common operations than the simple singly-linked list that F# uses.
What advantages does dropping the tail pointer have?
30% less space usage and better performance on virtually all list operations.

Am I missing something, or do we have a couple inconsistencies / misnomers?

Mathematicians typically count starting with 1, and call the counting variable n (i.e. "the nth term of the sequence). Computer scientists typically count starting with 0, and call the counting variable i (i.e. "the ith index of the array"). Which is why I was confused to learn that Seq.nth actually returns the "n+1 term of the sequence".
Doubly confusing is that Seq.iteri does as it's name implies and traverses a sequence supplying the current index.
Am I missing something? Is there a rational / history for this misnomer / inconsistency? Or was it just a mistake (which likely can't be fixed since we have a commercial release now).
Edit
Admittedly my claim about conventional use of i and n is not strictly true and I should have been more careful about such an assertion. But I think it is hard to deny that the most popularly used languages do start counting at 0 and that i and j are most certainly extremely popular choices for index variable names. So, when I am familiar with using Seq.iteri and Seq.mapi and then come across Seq.nth I think it is reasonable to think, "Oh, this function counts differently, probably the other way things are counted, starting with 1."
And, as I pointed out in the comments, the summaries for Seq.iteri, Seq.mapi, and Seq.nth only served to enforce my assumption (note that intellisense only gives you the summaries, it does not give you the description of each parameter which you have to find on MSDN):
Seq.iter
Applies the given function to each
element of the collection. The integer
passed to the function indicates the
index of element.
Seq.mapi
Creates a new collection whose
elements are the results of applying
the given function to each of the
elements of the collection. The
integer index passed to the function
indicates the index (from 0) of
element being transformed.
Seq.nth
Computes the nth element in the
collection.
Note the emphasis on "nth", not mine, as if everyone knows what the nth element in the sequences is as opposed to the ith element.
Talking of history, nth is zero based in Lisp, which is probably what the F# function is named for. See the common lisp spec for nth.
I haven't found your statement about i and n in mathematics to be true; usually n is the number of something rather than an index. In this case, it was the number of times to call cdr to get the next element.
Arrays are indexed starting from 0 in many computer languages, but some languages start from 1 and some allow a choice. Some allow the index range to be set as part of the array declaration, or even to be changed at runtime.
Mathematicians are as likely to start at zero as one, sometimes use other index ranges, and attach no particular meaning to the letters 'n' and 'i'.
The method names Seq.nth and Seq.iteri are poorly named.

How to determine whether a linked list contains a loop? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
find whether a loop in a linked list without two pointers
How to determine if a linked list has a cycle using only two memory locations.
Best algorithm to test if a linked list has a cycle
During a preparation for a job interview, I encountered the following question:
How can you determine whether a linked list (of any type) contains a loop, using additional space complexity of O(1)? You cannot assume that the loop starts at the first node (and of course, the loop doesn't have to contain all nodes).
I couldn't find the answer, though I have the feeling it's quite simple...
Easy. Maintain two pointers into the list. At each step, advance one pointer by a single link, and advance the other by two links. Test to see if they point to the same element. If so, you have a loop. If not, repeat until you find a loop or you reach the end of the list.
Probably the same technique as checking if a graph is a tree (trees don't get to have cycles), see this this question. It recommends either a topological sort or a depth first search.
I had this exact problem in real live code last week.
All I did was kept a pointer (link) for the first element. Then as I iterated through the list, if I ever got that pointer again, I know there's a loop.

Resources