Merge sort on a double linked list - sorting

Reading up on the good ways to sort a linked list (besides assigning an array and quick-sorting), it looks like mergesort is one of the better methods.
See: Merge Sort a Linked List
The current questions on this topic are non-specific as to weather the list is single or double linked.
My question is:
Is there improved methods of merge-sorting that take advantage of double linked lists?
(or is it just as good to use the same method as a single linked list and assign the previous link just to ensure the list remains valid)

To the best of my knowledge, there are no special time-saving tricks that arise when doing mergesort on a doubly-linked list that don't also work on a singly-linked list.
Mergesort was originally developed for data stored on reels of magnetic tape that could only be read in a forwards direction, and most standard implementations of mergesort only do forwards passes over the elements. The two major operations required by mergesort are splitting the input in half (hard in both singly- and doubly-linked lists) and merging elements back together (basically the same in both cases). As a result, without doing something substantially more clever than a standard mergesort, I would not expect there to be any major speedups.

Related

When is a linked list the best data structure to use

like the title really. My question is can you give an example where a linked list is the BEST data structure to use. I have been struggling to think of any really, and in my code I pretty much always just use hashmaps or lists etc.
http://bigocheatsheet.com/ Here you can see the cheat sheet of Big O's for various operations. A linked list is no better than a stack or a queue in terms of complexity. And so I wanted to know when someone might use a linked list over these for example? A perfect answer will say "Imagine I was trying to do XYZ, if I did it with an array it would look like this {enter some code}, however, if I do it with a linked list, it will look like this {enter more code}. The complexities or space are substantially better for the linked list." etc.
I don't want an answer where someone tells me WHAT a linked list is. I know what a linked list is and how they are implemented.
Thanks
Consider if you have a line-up of people, and somewhere in the middle you want to add a lot of people. If you used a conventional ArrayList, you would need to shift all elements after it, so O(N) because of indexing per person! In a LinkedList, each person would be O(1), with O(N) to get to the middle. Linked Lists are very quick in adding elements in the middle, as you don't need to reindex anything and just adjust the local pointer.
Someone dd a survey of the C++ standard template library and found that the linked list was the least used of all the common basic structures. So you're right they they are not much used. They're useful when you don't need random access to an array, when you don't know N or have a reasonably tight upper bound on N, and when insertions and deletions are common and time critical. An insertion in the middle is O(N), as with an array, but the actual operation is a lot cheaper (pointer dereference rather than memory shifting), insertions at the beginning are O(1), and at the end if you keep an end pointer.

Search multiple lists by indirective ids

There are x (x=3 in this example) unsorted lists with identificators:
list1 list2 list3
array1[id3], array2[id4,id4a], array3[id1a,id1b]
array1[id4], array2[id3,id3a], array3[id4a,id4b]
array1[id1], array2[id2,id2a], array3[id3a,id3b]
array1[id2], array2[id1,id1a], array3[id2a,id2b]
...
array1[idn], array2[idn,idna], array3[idn,idnb]
I want to make pairs: {id1,id1b}, {id2,id2b} and so on. Sadly, i cannot do it directly. That's how it works: take id3 from list1 then find id3 in list2 then take id3a from list2 then find id3a in list3 and finally we got id3b.
It could be done with nested loops but what if there were more lists? Seems to be inefficient. Is there a better solution?
The only better solutions algorithmically would require a different representation. For example, if the lists can be sorted, then searches to get from key1->key2->key3->value could all be binary searches. That's probably the easiest and least intrusive solution to implement if you can just slightly change the data representation to be sorted.
If you use a different data structure outright like multiple hash tables, then each search could be constant-time (assuming no collisions). You could even consolidate this all to a single hash table with a 3-part key that maps to a single hash index storing the value.
You could also use BSTs, possibly tries, etc., but all of these algorithmic improvements will hinge on a different data representation.
Any search through an unsorted list is generally going to have to be O(N), since we cannot make any assumptions and are helpless but to potentially search the entire list. With three lists and 3 nested searches, we end up looking at a cubic complexity O(N^3) algorithm (doesn't scale very well).
Without changing the data representation, I think linear-time searches for each unsorted list is as good as you can get (and yes, that could be quite horrible), and you're probably looking at micro-optimizations like multithreading or SIMD.
I forgot to mention that after each iteration i'll get a new set of lists.
For example, in the first iteration:
array1[id1], array2[id2,id2a], array3[id3a,id3b]
array1[id2], array2[id1,id1a], array3[id2a,id2b]`
In the second one:
array1[id3], array2[id4,id4a], array3[id1a,id1b]
array1[id4], array2[id3,id3a], array3[id4a,id4b]
etc. So if I touch the keys to link them together in one iteration I will have to do the same in next one with the new set. It looks like each auxiliary structure has to be rebuilt. is it worthwhile then? No doubt, it depends. But more or less?

Why is having multiple heads for a singly-linked list a good thing?

In this post, When is doubly linked list more efficient than singly linked list?, rici explains:
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.
How can having multiple heads be a good thing?
It's not inherently a good thing. It's just the natural outcome of lazy copying of immutable linked-lists.
Imagine:
LinkedList a = createLinkedList(...);
LinkedList b = prepend(a, 3.14);
LinkedList c = prepend(a, 2.72);
If the contents are lazily copied (which is a natural choice if lists are immutable), then the first elements of b and c now both point at the first element of a.
I'd say that if it makes sense to have multiple lists where parts of their tails are the same in your code, then representing them as lists that share those tails is a good thing, because it saves memory.
But, if something like that isn't useful for you, then this ability won't give you anything.

implement linked list using array - advantages & disadvantages

I know how to implement linked list using array. For example
we define a struct as follow:
struct Node{
int data;
int link;
}
"data" stores the info and "link" stores the index in the array of next node.
Can anybody tell me what is the advantage and disadvantage of implementing a linked list using array compared to "ordinary" linked list? Any suggestion will be appreciated.
If you back a linked list with an array, you'll end up with the disadvantages of both. Consequently, this is probably not a very good way to implement it.
Some immediate disadvantages:
You'll have dead space in the array (entries which aren't currently used for items) taking up memory
You'll have to keep track of the free entries - after a few insertions and deletions, these free entries could be anywhere.
Using an array will impose an upper limit on the size of the linked list.
I suppose some advantages are:
If you're on a 64 bit system, your "pointers" will take up less space (though the extra space required by free entries probably outweighs this advantage)
You could serialise the array to disk and read it back in with an mmap() call easily. Though, you'd be better off using some sort of protocol buffer for portability.
You could make some guarantees about elements in the array being close to each other in memory.
Can anybody tell me what is the advantage and disadvantage of implementation of linked list using array compared to "ordinary" linked list?
linked lists have the following complexity:
cons x xs : O(1)
append n m : O(n)
index i xs : O(n)
if your representation uses a strict, contiguous array, you will have different complexity:
cons will require copying the old array: O(n)
append will require copying both arrays into a new contiguous space: O(n + m)
index can be implemented as array access: O(1)
That is, a linked list API implemented in terms of arrays will behave like an array.
You can mitigate this somewhat by using a linked list or tree of strict arrays, leading to ropes or finger trees or lazy sequences.
stack in implement two way.
first in using array and second is using linked list.
some disadvatages in using array then most of programmer use linked list in stack implement.
first is stack using linked list first not declare stack size and not limited data store in stack. second is linked list in pointer essay to declare and using it.
only one pointer use in linked list. its called top pointer.
stack is lifo method use. but some disadvantages in linked list program implemention.
Most of programmer use stack implemention using liked list.
Using Array implementation, you can have sequential & faster access to nodes of list, on the other hand,
If you implement Linked list using pointers, you can have random access to nodes.
Array implementation is helpful when you are dealing with fixed no. Of elements because resizing an array is expensive as far as performance is concerned because if you are required to insert/delete nodes from middle of the list it you have to shift every node afterwise.
Contrary to this, You should use pointer implemention when you don't know no. of nodes you would want, as such a list can grow/shrink efficiently & you don't need to shift any nodes, it can be done by simply dereferencing & referencing pointers.

Why is appending to a list bad?

I've recently started learning scala, and I've come across the :: (cons) function, which prepends to a list.
In the book "Programming in Scala" it states that there is no append function because appending to a list has performance o(n) whereas prepending has a performance of o(1)
Something just strikes me as wrong about that statement.
Isn't performance dependent on implementation? Isn't it possible to simply implement the list with both forward and backward links and store the first and last element in the container?
The second question I suppose is what I'm supposed to do when I have a list, say 1,2,3 and I want to add 4 to the end of it?
The key is that x :: somelist does not mutate somelist, but instead creates a new list, which contains x followed by all elements of somelist. This can be done in O(1) time because you only need to set somelist as the successor of x in the newly created, singly linked list.
If doubly linked lists were used instead, x would also have to be set as the predecessor of somelist's head, which would modify somelist. So if we want to be able to do :: in O(1) without modifying the original list, we can only use singly linked lists.
Regarding the second question: You can use ::: to concatenate a single-element list to the end of your list. This is an O(n) operation.
List(1,2,3) ::: List(4)
Other answers have given good explanations for this phenomenon. If you are appending many items to a list in a subroutine, or if you are creating a list by appending elements, a functional idiom is to build up the list in reverse order, cons'ing the items on the front of the list, then reverse it at the end. This gives you O(n) performance instead of O(n²).
Since the question was just updated, it's worth noting that things have changed here.
In today's Scala, you can simply use xs :+ x to append an item at the end of any sequential collection. (There is also x +: xs to prepend. The mnemonic for many of Scala's 2.8+ collection operations is that the colon goes next to the collection.)
This will be O(n) with the default linked implementation of List or Seq, but if you use Vector or IndexedSeq, this will be effectively constant time. Scala's Vector is probably Scala's most useful list-like collection—unlike Java's Vector which is mostly useless these days.
If you are working in Scala 2.8 or higher, the collections introduction is an absolute must read.
Prepending is faster because it only requires two operations:
Create the new list node
Have that new node point to the existing list
Appending requires more operations because you have to traverse to the end of the list since you only have a pointer to the head.
I've never programmed in Scala before, but you could try a List Buffer
Most functional languages prominently figure a singly-linked-list data structure, as it's a handy immutable collection type. When you say "list" in a functional language, that's typically what you mean (a singly-linked list, usually immutable). For such a type, append is O(n) whereas cons is O(1).

Resources