Code translated to C from Wirth's book is following
void quicksort(int *array, int left, int right)
{
int v=array[(left+right)/2];
int i,j,x;
i=left;
j=right;
do {
while (array[i]<v) i++;
while (array[j]>v) j--;
if (i<=j) {
x=array[i];
array[i]=array[j];
array[j]=x;
i++;
j--;
}
} while (i<=j);
if (j>left) quicksort(array, left, j);
if (i<right) quicksort(array, i, right);
}
but that uses arrays - my stab at doubly linked lists (node structure here ):
void partitonSort(node **head,node **tail)
{
node *v; // here I want to use first or last element as pivot
node *i,*j;
do
{
while(i->key < v->key) i = i->next;
while(j->key > v->key) j = j->prev;
if(/*what boolean expression should I use here*/)
{
/*Is it necessary to replace swap operation
with insert and delete operations and
how to do it */
i = i->next;
j = j->prev;
}
}
while(/*what boolean expression should I use here*/);
if(/*what boolean expression should I use here*/)
partitonSort(head,&j);
if(/*what boolean expression should I use here*/)
partitonSort(&i,tail);
}
I left questions in the code comments:
- Should I replace swap operation with insert and delete
and how to do this
- What boolean expressions I should use
Here is my concise solution with detailed comments:
/* a node of the doubly linked list */
struct Node
{
int data;
struct Node *next;
struct Node *prev;
};
/* A utility function to swap two elements */
void swap ( int* a, int* b )
{ int t = *a; *a = *b; *b = t; }
// A utility function to find last node of linked list
struct Node *lastNode(Node *root)
{
while (root && root->next)
root = root->next;
return root;
}
/* Considers last element as pivot, places the pivot element at its
correct position in sorted array, and places all smaller (smaller than
pivot) to left of pivot and all greater elements to right of pivot */
Node* partition(Node *l, Node *h)
{
// set pivot as h element
int x = h->data;
// similar to i = l-1 for array implementation
Node *i = l->prev;
// Similar to "for (int j = l; j <= h- 1; j++)"
for (Node *j = l; j != h; j = j->next)
{
if (j->data <= x)
{
// Similar to i++ for array
i = (i == NULL)? l : i->next;
swap(&(i->data), &(j->data));
}
}
i = (i == NULL)? l : i->next; // Similar to i++
swap(&(i->data), &(h->data));
return i;
}
/* A recursive implementation of quicksort for linked list */
void _quickSort(struct Node* l, struct Node *h)
{
if (h != NULL && l != h && l != h->next)
{
struct Node *p = partition(l, h);
_quickSort(l, p->prev);
_quickSort(p->next, h);
}
}
// The main function to sort a linked list. It mainly calls _quickSort()
void quickSort(struct Node *head)
{
// Find last node
struct Node *h = lastNode(head);
// Call the recursive QuickSort
_quickSort(head, h);
}
Yes but I prefer to change links instead of data
Here is pseudocode
PartitionSort(L)
if head[L] != tail[L] then
//Choose the pivot node, first node or last node is the option
pivot := tail[L]
//Partition step, we distribute nodes of the linked list into three sublists
curr := head
while curr != NULL do
if key[curr] < key[pivot] then
pushBack(curr,Less)
else if key[curr] = key[pivot] then
pushBack(curr,Equal)
else
pushBack(curr,Greater)
end if
end if
curr := next[curr]
end while
// Here me make sure that we partitioned linked list correctly
// We should set next of tail pointers and prev of head pointers to NULL
//Now we do recursive calls on sublists with keys not equal to the pivot key
PartitionSort(Less)
PartitionSort(Greater)
// Now we concatenate sublists
if tail[Less] != NULL then
next[tail[Less]] := head[Equal]
else
head[Less] := head[Equal]
end if
if head[Equal] then
prev[head[Equal]] = tail[Less]
tail[Less] = tail[Equal]
end if
if tail[Less] != NULL then
next[tail[Less]] := head[Greater]
else
head[Less] := head[Greater]
end if
if head[Greater] then
prev[head[Greater]] = tail[Less]
tail[Less] = tail[Greater]
end if
L := Less
end if
I traverse the nodes of a tree in depth-first manner. Suppose the tree is as follows:
Now, suppose that I am in node E and for some condition I want to back to the node C and continue from there. Then previous traversing should be canceled and node C, D, E should be evaluated again. Node F and G shouldn't be traversed twice as the previous recursive navigation has been cancelled!
Usual navigation : A B C D E F G
The desire navigation : A B C D E C D E F G
The general code of depth-first traversing is as follows:
void DFS(node x)
{
z = evaluate(x);
// if (z != null) DFS(z)
// Z could be a node which has been already traversed,
// let's suppose it's an ancestor of x
foreach (node y in c.children)
{
DFS(y);
}
}
Please help me how can I have such navigation in the tree?
I will try to outline a pseudocode using a global variable cancel.
boolean cancel = false;
void DFS(node x, parent p)
{
if(!cancel) {
foreach (node y in x.children) {
DFS(y, x);
}
} else {
cancel = false;
DFS(p, findParent(p));
}
}
However, there is a problem with this approach. Once the traversal has started in the foreach section, each subsequent call to the DFS method within the loop will invoke the DFS from parent node. To address this concern, I would recommend you to simulate the depth first traversal by using your own stack rather than taking the recursive approach. That way, when cancel becomes true, you can clear the stack and ensure that DFS call from the parent happens only once. Hope this helps!
Something among the following lines should work:
boolean cancel = false;
Stack<Node> s;
void DFSIterative(Node x, Node p) {
if(cancel) {
resetDFS(p);
} else {
s.push(x);
while(!s.isEmpty()) {
x = s.pop();
p = findParent(x);
if(cancel) resetDFS;
else {
foreach(node y in x.children) {
s.push(y);
}
}
}
}
}
void resetDFS(Node p) {
s.clear();
cancel = false;
DFSIterative(p, findParent(p));
}
I leave the implementation of findParent() helper method to you. Please note that you will also need to take care of marking the nodes as visited and then unmarking relevant nodes as unvisited when you cancel DFS.
Depending on how far back up the tree you want to go, something like this should work.
The DFS function returns the number of levels to retry:
0 to carry on as normal
1 to retry the same node
2 to retry the parent...
Code:
int DFS(node x)
{
if (some condition)
{
// return the number of parent levels you want to back up
return 2;
}
for (int i = 0; i < x.children.size; ++i)
{
int redo = DFS(x.children[i]);
if (redo == 1) {
// redo == 1 means retry the current node
--i;
}
if (redo > 1) {
{
// redo > 1 means retry an ancestor node
return redo - 1;
}
}
return 0;
}
Obviously you have to be careful with your condition, or you'll end up in an infinite loop.
With the base code as above, the following condition will return A B C D E C D E F G
boolean retryE = true;
int DFS(node x)
{
if (x.value == "E" && retryE)
{
retryE = false;
return 2;
}
// remaining code as above
}
Update
Looking again, if your evaluate function returns an ancestor node not a number of levels, this may be closer to what you originally wanted... Will fail if the node returned is not an ancestor of the current child...
// returns null to continue DFS, or a node value to repeat from that node
Node DFS(Node x)
{
Node z = evaluate(x)
if (z != null)
{
return z;
}
for (int i = 0; i < x.children.size; ++i)
{
Node child = x.children[i];
Node result = DFS(child);
if (result != null)
{
if (result == child)
{
// current child is the one to retry so just
// decrement the counter to retry it
--i;
} else {
// retry a node but not this child so return it up the stack
return result;
}
}
}
return null;
}
Update 2
Using the same DFS function, consider this evaluate function, which returns C for the first occurence of both E and F
boolean retryE = true;
boolean retryF = true;
evaluate(Node x)
{
if (x.value == "E" && retryE)
{
retryE = false;
return C;
}
if (x.value == "F" && retryF)
{
retryF = false;
return C;
}
return null;
}
This will work correctly using the --i decrement method (returning A B C D E - C D E F - C D E F G), but not if calling DFS(child) directly, unless the result of the second call is processed somehow.
Cheers
See here I can see that u have used a void DFS that is your function is not returning anything so you can use that value to check if something is need to be reevaluated.
Like this
int DFS(node x)
{
int ret=0;
z = evaluate(x);
// if (z != null) DFS(z) Z could be a node which has been already traversed
foreach (node y in c.children)
{
ret=DFS(y);
if(ret==1)
break;
}
if(ret==1)
DFS(x);
if(z==(want to reevaluate))
return 1;
else
return 0;
}
Now by this you can simply return to the parent 1 if you want it to redo the DFS on all its children and you can simply return 0 if you want it to simply continue.
If any of the children of A returned 1 in that case All the children and that node will be reevaluated and the nodes above it will continue in the same way as they were.
So by you image.If E returns 1 then all of the nodes C,D,E will be reevaluated. If you have return value fixed to return distance or something then this could be done using a variable also, you just need to send its address to all the children and watch for its value.
I am working on implementing a quicksort function to sort singly linked lists. What algorithm would I have to use to accomplish this ? For a linked list it would take worst case O(N) for each comparison, instead of the usual O(1) for arrays. So what would the worst case complexity be ?
To sum up, what modifications do I need to make to the quicksort algorithm to have an optimal sorting algorithm and what would be the worst case complexity of the algorithm ?
Thanks!
I have an implementation below:
public static SingleLinkedList quickSort(SingleLinkedList list, SLNode first, SLNode last)
{
if (first != null && last != null)
{
SLNode p = partition(list, first, last) ;
quickSort(list,first,p) ;
quickSort(list,p.succ, last) ;
}
return list ;
}
public static SLLNode partition(SinlgleLinkedList list, SLNode first, SLNode last)
{
SLNode p = first ;
SLNode ptr = p.succ ;
while (ptr!=null)
{
if (ptr.data.compareToIgnoreCase(p.data)<0)
{
String pivot = p.data ;
p.data = ptr.data ;
ptr.data = p.succ.data ;
p.succ.data = pivot ;
p = p.succ ;
}
ptr = ptr.succ ;
}
return p ;
}
Mergesort is more natural to implement for linked lists, but you can do quicksort very nicely. Below is one in C I've used in several applications.
It's a common myth that you can't do Quicksort efficiently with lists. This just isn't true, although careful implementation is required.
To answer your question, the Quicksort algorithm for lists is essentially the same as for arrays. Pick a pivot (the code below uses the head of the list), partition into two lists about the pivot, then recursively sort those lists and append the results with pivot in the middle. What is a bit non-obvious is that the append operation can be done with no extra pass over the list if you add a parameter for a list to be appended as-is at the tail of the sorted result. In the base case, appending this list requires no work.
It turns out that if comparisons are cheap, mergesort tends to run a little faster because quicksort spends more time fiddling with pointers. However if comparisons are expensive, then quicksort often runs faster because it needs fewer of them.
If NODE *list is the head of the initial list, then you can sort it with
qs(list, NULL, &list);
Here is the sort code. Note a chunk of it is an optimization for already-sorted lists. This optimization can be deleted if these cases are infrequent.
void qs(NODE * hd, NODE * tl, NODE ** rtn)
{
int nlo, nhi;
NODE *lo, *hi, *q, *p;
/* Invariant: Return head sorted with `tl' appended. */
while (hd != NULL) {
nlo = nhi = 0;
lo = hi = NULL;
q = hd;
p = hd->next;
/* Start optimization for O(n) behavior on sorted and reverse-of-sorted lists */
while (p != NULL && LEQ(p, hd)) {
hd->next = hi;
hi = hd;
++nhi;
hd = p;
p = p->next;
}
/* If entire list was ascending, we're done. */
if (p == NULL) {
*rtn = hd;
hd->next = hi;
q->next = tl;
return;
}
/* End optimization. Can be deleted if desired. */
/* Partition and count sizes. */
while (p != NULL) {
q = p->next;
if (LEQ(p, hd)) {
p->next = lo;
lo = p;
++nlo;
} else {
p->next = hi;
hi = p;
++nhi;
}
p = q;
}
/* Recur to establish invariant for sublists of hd,
choosing shortest list first to limit stack. */
if (nlo < nhi) {
qs(lo, hd, rtn);
rtn = &hd->next;
hd = hi; /* Eliminated tail-recursive call. */
} else {
qs(hi, tl, &hd->next);
tl = hd;
hd = lo; /* Eliminated tail-recursive call. */
}
}
/* Base case of recurrence. Invariant is easy here. */
*rtn = tl;
}
Here is a java implementation. It uses the head as the pivot. This can further be improved by avoiding the scanning of the left sublist before appending the right sublist, but it works. This is O(nLogn) too.
public class QuickSortLinkedList {
public ListNode sortList(ListNode head) {
//Base Case
if(head == null || head.next == null)
return head;
//Partition Strategy
//Chose first element as pivot and move all elements smaller than the pivot at the end of LL
//So the order will be pivot, elements smaller than or equal to pivot, elements larger than pivot
//Example: 9,13,10,6,9,8,11 => 9,13,10,9,11,6,8 and the method will return a pointer to 11
ListNode partitionedElement = partition(head);
//The elements to the right of pivot were all smaller than pivot after partioned
//Example: LeftPartition = 6->8->null
ListNode leftPartition = partitionedElement.next;
//The elements to the left of pivot were all large , so they go in right partition
//Example: rightPartition = 9->13->10->9->11->null
ListNode rightPartition = head;
partitionedElement.next = null;
//But there can be edge cases
//Example: 3,5,3,4,5-null => after partition , list is unchanged and last element 5 is returned
//in this case leftPartition: 3->null and rightPartition 5,3,4,5-null
if(leftPartition == null){
leftPartition = head;
rightPartition = head.next;
head.next =null;
}
//Now Recursively sort
rightPartition = sortList(rightPartition);
leftPartition = sortList(leftPartition);
//After sorting append rightPartition to leftPartition
ListNode iterator = leftPartition;
while(iterator.next!=null)
iterator = iterator.next;
iterator.next = rightPartition;
return leftPartition;
}
private ListNode partition(ListNode head){
//Base case
if(head.next.next == null){
if(head.next.val>head.val)
return head.next;
else
return head;
}
else{
ListNode i = head.next;
ListNode pivot = head;
ListNode lastElementSwapped = (pivot.next.val>=pivot.val)?pivot.next:pivot;
while(i!=null && i.next !=null){
if(i.next.val >= pivot.val){
if(i.next == lastElementSwapped.next){
lastElementSwapped = lastElementSwapped.next;
}
else{
ListNode temp = lastElementSwapped.next;
lastElementSwapped.next = i.next;
i.next = i.next.next;
lastElementSwapped = lastElementSwapped.next;
lastElementSwapped.next = temp;
}
}
i = i.next;
}
return lastElementSwapped;
}
}
}
You can use quicksort and not lose the O(n*log(n)) expected behaviour. The trick is simple — the nodes into the array, sort the array of nodes, relink them in the correct order.
You can use this algorithm:
Choose the head node as pivot node.
The left partition starts with the pivot node, which will remain its tail
The right partition starts empty
For each node: pre-pend it to either the left or right partition list, setting its next reference to the current head of that partition, and making it its new head.
Since the pivot element is the tail node of the left partition, set its next reference to null, so to really terminate that list there.
Apply recursion on the left and right partition, returning its potentially modified head references.
Tie the two sorted sublists together. As the tail node of the left partition is guaranteed to remain there and was the pivot node, set its next reference to the head of the second, sorted partition.
Return the head of the sorted list.
Recursion stops when the base is encountered, which is when the list has fewer than 2 nodes.
This has an average time complexity of O(nlogn). The worst time complexity is O(n²). For instance, when the list is already sorted it will suffer this time complexity.
Here is a singly linked list implementation in Python with a quick_sort method:
class Node:
def __init__(self, data, nxt=None):
self.data = data
self.next = nxt
def __iter__(self):
curr = self
while curr:
node = curr
curr = curr.next
yield node
def values(self):
return (node.data for node in self)
def partition(self):
nodes = iter(self) # All nodes headed by this node
next(nodes) # Skip self
left = self # Left partition always has pivot node as its tail
pivotvalue = self.data
right = None
for curr in nodes: # Remaining nodes
# Prefix the current node to the relevant partition
if curr.data < pivotvalue:
curr.next = left
left = curr
else:
curr.next = right
right = curr
self.next = None # Terminate the left partition
return left, right
def quick_sort(self):
if not self.next: # Base case: one node only
return self
left, right = self.partition()
# Left partition has at least one node (the pivot node, which remains its tail)
left = left.quick_sort()
# Right partition could be empty
if right:
right = right.quick_sort()
self.next = right # Chain the two sorted partitions
return left
def is_sorted(self):
values = self.values()
prev = next(values)
for data in values:
if data < prev:
return False
prev = data
return True
class LinkedList:
def __init__(self, *values):
self.head = None
self.prefix(*values)
def prefix(self, *values):
for data in reversed(values):
self.head = Node(data, self.head)
def values(self):
if self.head:
return self.head.values()
def quick_sort(self):
self.head = self.head and self.head.quick_sort()
def is_sorted(self):
return self.head is not None and self.head.is_sorted()
Here is some code to test this implementation repeatedly with shuffled lists of 20 values:
from random import shuffle
values = list(range(20))
for _ in range(100):
shuffle(values)
linkedlist = LinkedList(*values)
print("Shuffled:", *linkedlist.values())
linkedlist.quick_sort()
print("Sorted:", *linkedlist.values())
if not linkedlist.is_sorted(): # Test for failure
raise ValueError("not sorted!")
I was recently brushing up on some fundamentals and found merge sorting a linked list to be a pretty good challenge. If you have a good implementation then show it off here.
Wonder why it should be big challenge as it is stated here, here is a straightforward implementation in Java with out any "clever tricks".
//The main function
public static Node merge_sort(Node head)
{
if(head == null || head.next == null)
return head;
Node middle = getMiddle(head); //get the middle of the list
Node left_head = head;
Node right_head = middle.next;
middle.next = null; //split the list into two halfs
return merge(merge_sort(left_head), merge_sort(right_head)); //recurse on that
}
//Merge subroutine to merge two sorted lists
public static Node merge(Node a, Node b)
{
Node dummyHead = new Node();
for(Node current = dummyHead; a != null && b != null; current = current.next;)
{
if(a.data <= b.data)
{
current.next = a;
a = a.next;
}
else
{
current.next = b;
b = b.next;
}
}
dummyHead.next = (a == null) ? b : a;
return dummyHead.next;
}
//Finding the middle element of the list for splitting
public static Node getMiddle(Node head)
{
if(head == null)
return head;
Node slow = head, fast = head;
while(fast.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
A simpler/clearer implementation might be the recursive implementation, from which the NLog(N) execution time is more clear.
typedef struct _aList {
struct _aList* next;
struct _aList* prev; // Optional.
// some data
} aList;
aList* merge_sort_list_recursive(aList *list,int (*compare)(aList *one,aList *two))
{
// Trivial case.
if (!list || !list->next)
return list;
aList *right = list,
*temp = list,
*last = list,
*result = 0,
*next = 0,
*tail = 0;
// Find halfway through the list (by running two pointers, one at twice the speed of the other).
while (temp && temp->next)
{
last = right;
right = right->next;
temp = temp->next->next;
}
// Break the list in two. (prev pointers are broken here, but we fix later)
last->next = 0;
// Recurse on the two smaller lists:
list = merge_sort_list_recursive(list, compare);
right = merge_sort_list_recursive(right, compare);
// Merge:
while (list || right)
{
// Take from empty lists, or compare:
if (!right) {
next = list;
list = list->next;
} else if (!list) {
next = right;
right = right->next;
} else if (compare(list, right) < 0) {
next = list;
list = list->next;
} else {
next = right;
right = right->next;
}
if (!result) {
result=next;
} else {
tail->next=next;
}
next->prev = tail; // Optional.
tail = next;
}
return result;
}
NB: This has a Log(N) storage requirement for the recursion. Performance should be roughly comparable with the other strategy I posted. There is a potential optimisation here by running the merge loop while (list && right), and simple appending the remaining list (since we don't really care about the end of the lists; knowing that they're merged suffices).
Heavily based on the EXCELLENT code from: http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
Trimmed slightly, and tidied:
typedef struct _aList {
struct _aList* next;
struct _aList* prev; // Optional.
// some data
} aList;
aList *merge_sort_list(aList *list,int (*compare)(aList *one,aList *two))
{
int listSize=1,numMerges,leftSize,rightSize;
aList *tail,*left,*right,*next;
if (!list || !list->next) return list; // Trivial case
do { // For each power of two<=list length
numMerges=0,left=list;tail=list=0; // Start at the start
while (left) { // Do this list_len/listSize times:
numMerges++,right=left,leftSize=0,rightSize=listSize;
// Cut list into two halves (but don't overrun)
while (right && leftSize<listSize) leftSize++,right=right->next;
// Run through the lists appending onto what we have so far.
while (leftSize>0 || (rightSize>0 && right)) {
// Left empty, take right OR Right empty, take left, OR compare.
if (!leftSize) {next=right;right=right->next;rightSize--;}
else if (!rightSize || !right) {next=left;left=left->next;leftSize--;}
else if (compare(left,right)<0) {next=left;left=left->next;leftSize--;}
else {next=right;right=right->next;rightSize--;}
// Update pointers to keep track of where we are:
if (tail) tail->next=next; else list=next;
// Sort prev pointer
next->prev=tail; // Optional.
tail=next;
}
// Right is now AFTER the list we just sorted, so start the next sort there.
left=right;
}
// Terminate the list, double the list-sort size.
tail->next=0,listSize<<=1;
} while (numMerges>1); // If we only did one merge, then we just sorted the whole list.
return list;
}
NB: This is O(NLog(N)) guaranteed, and uses O(1) resources (no recursion, no stack, nothing).
One interesting way is to maintain a stack, and only merge if the list on the stack has the same number of elements, and otherwise push the list, until you run out of elements in the incoming list, and then merge up the stack.
The simplest is from
Gonnet + Baeza Yates Handbook of Algorithms. You call it with the number of sorted elements you want, which recursively gets bisected until it reaches a request for a size one list which you then just peel off the front of the original list. These all get merged up into a full sized sorted list.
[Note that the cool stack-based one in the first post is called the Online Mergesort and it gets the tiniest mention in an exercise in Knuth Vol 3]
Here's an alternative recursive version. This does not need to step along the list to split it: we supply a pointer to a head element (which is not part of the sort) and a length, and the recursive function returns a pointer to the end of the sorted list.
element* mergesort(element *head,long lengtho)
{
long count1=(lengtho/2), count2=(lengtho-count1);
element *next1,*next2,*tail1,*tail2,*tail;
if (lengtho<=1) return head->next; /* Trivial case. */
tail1 = mergesort(head,count1);
tail2 = mergesort(tail1,count2);
tail=head;
next1 = head->next;
next2 = tail1->next;
tail1->next = tail2->next; /* in case this ends up as the tail */
while (1) {
if(cmp(next1,next2)<=0) {
tail->next=next1; tail=next1;
if(--count1==0) { tail->next=next2; return tail2; }
next1=next1->next;
} else {
tail->next=next2; tail=next2;
if(--count2==0) { tail->next=next1; return tail1; }
next2=next2->next;
}
}
}
I'd been obsessing over optimizing clutter for this algorithm and below is what I've finally arrived at. Lot of other code on Internet and StackOverflow is horribly bad. There are people trying to get middle point of the list, doing recursion, having multiple loops for left over nodes, maintaining counts of ton of things - ALL of which is unnecessary. MergeSort naturally fits to linked list and algorithm can be beautiful and compact but it's not trivial to get to that state.
Below code maintains minimum number of variables and has minimum number of logical steps needed for the algorithm (i.e. without making code unmaintainable/unreadable) as far as I know. However I haven't tried to minimize LOC and kept as much white space as necessary to keep things readable. I've tested this code through fairly rigorous unit tests.
Note that this answer combines few techniques from other answer https://stackoverflow.com/a/3032462/207661. While the code is in C#, it should be trivial to convert in to C++, Java, etc.
SingleListNode<T> SortLinkedList<T>(SingleListNode<T> head) where T : IComparable<T>
{
int blockSize = 1, blockCount;
do
{
//Maintain two lists pointing to two blocks, left and right
SingleListNode<T> left = head, right = head, tail = null;
head = null; //Start a new list
blockCount = 0;
//Walk through entire list in blocks of size blockCount
while (left != null)
{
blockCount++;
//Advance right to start of next block, measure size of left list while doing so
int leftSize = 0, rightSize = blockSize;
for (;leftSize < blockSize && right != null; ++leftSize)
right = right.Next;
//Merge two list until their individual ends
bool leftEmpty = leftSize == 0, rightEmpty = rightSize == 0 || right == null;
while (!leftEmpty || !rightEmpty)
{
SingleListNode<T> smaller;
//Using <= instead of < gives us sort stability
if (rightEmpty || (!leftEmpty && left.Value.CompareTo(right.Value) <= 0))
{
smaller = left; left = left.Next; --leftSize;
leftEmpty = leftSize == 0;
}
else
{
smaller = right; right = right.Next; --rightSize;
rightEmpty = rightSize == 0 || right == null;
}
//Update new list
if (tail != null)
tail.Next = smaller;
else
head = smaller;
tail = smaller;
}
//right now points to next block for left
left = right;
}
//terminate new list, take care of case when input list is null
if (tail != null)
tail.Next = null;
//Lg n iterations
blockSize <<= 1;
} while (blockCount > 1);
return head;
}
Points of interest
There is no special handling for cases like null list of list of 1 etc required. These cases "just works".
Lot of "standard" algorithms texts have two loops to go over leftover elements to handle the case when one list is shorter than other. Above code eliminates need for it.
We make sure sort is stable
The inner while loop which is a hot spot evaluates 3 expressions per iteration on average which I think is minimum one can do.
Update: #ideasman42 has translated above code to C/C++ along with suggestions for fixing comments and bit more improvement. Above code is now up to date with these.
I decided to test the examples here, and also one more approach, originally written by Jonathan Cunningham in Pop-11. I coded all the approaches in C# and did a comparison with a range of different list sizes. I compared the Mono eglib approach by Raja R Harinath, the C# code by Shital Shah, the Java approach by Jayadev, the recursive and non-recursive versions by David Gamble, the first C code by Ed Wynn (this crashed with my sample dataset, I didn't debug), and Cunningham's version. Full code here: https://gist.github.com/314e572808f29adb0e41.git.
Mono eglib is based on a similar idea to Cunningham's and is of comparable speed, unless the list happens to be sorted already, in which case Cunningham's approach is much much faster (if its partially sorted, the eglib is slightly faster). The eglib code uses a fixed table to hold the merge sort recursion, whereas Cunningham's approach works by using increasing levels of recursion - so it starts out using no recursion, then 1-deep recursion, then 2-deep recursion and so on, according to how many steps are needed to do the sort. I find the Cunningham code a little easier to follow and there is no guessing involved in how big to make the recursion table, so it gets my vote. The other approaches I tried from this page were two or more times slower.
Here is the C# port of the Pop-11 sort:
/// <summary>
/// Sort a linked list in place. Returns the sorted list.
/// Originally by Jonathan Cunningham in Pop-11, May 1981.
/// Ported to C# by Jon Meyer.
/// </summary>
public class ListSorter<T> where T : IComparable<T> {
SingleListNode<T> workNode = new SingleListNode<T>(default(T));
SingleListNode<T> list;
/// <summary>
/// Sorts a linked list. Returns the sorted list.
/// </summary>
public SingleListNode<T> Sort(SingleListNode<T> head) {
if (head == null) throw new NullReferenceException("head");
list = head;
var run = GetRun(); // get first run
// As we progress, we increase the recursion depth.
var n = 1;
while (list != null) {
var run2 = GetSequence(n);
run = Merge(run, run2);
n++;
}
return run;
}
// Get the longest run of ordered elements from list.
// The run is returned, and list is updated to point to the
// first out-of-order element.
SingleListNode<T> GetRun() {
var run = list; // the return result is the original list
var prevNode = list;
var prevItem = list.Value;
list = list.Next; // advance to the next item
while (list != null) {
var comp = prevItem.CompareTo(list.Value);
if (comp > 0) {
// reached end of sequence
prevNode.Next = null;
break;
}
prevItem = list.Value;
prevNode = list;
list = list.Next;
}
return run;
}
// Generates a sequence of Merge and GetRun() operations.
// If n is 1, returns GetRun()
// If n is 2, returns Merge(GetRun(), GetRun())
// If n is 3, returns Merge(Merge(GetRun(), GetRun()),
// Merge(GetRun(), GetRun()))
// and so on.
SingleListNode<T> GetSequence(int n) {
if (n < 2) {
return GetRun();
} else {
n--;
var run1 = GetSequence(n);
if (list == null) return run1;
var run2 = GetSequence(n);
return Merge(run1, run2);
}
}
// Given two ordered lists this returns a list that is the
// result of merging the two lists in-place (modifying the pairs
// in list1 and list2).
SingleListNode<T> Merge(SingleListNode<T> list1, SingleListNode<T> list2) {
// we reuse a single work node to hold the result.
// Simplifies the number of test cases in the code below.
var prevNode = workNode;
while (true) {
if (list1.Value.CompareTo(list2.Value) <= 0) {
// list1 goes first
prevNode.Next = list1;
prevNode = list1;
if ((list1 = list1.Next) == null) {
// reached end of list1 - join list2 to prevNode
prevNode.Next = list2;
break;
}
} else { // same but for list2
prevNode.Next = list2;
prevNode = list2;
if ((list2 = list2.Next) == null) {
prevNode.Next = list1;
break;
}
}
}
// the result is in the back of the workNode
return workNode.Next;
}
}
Here is my implementation of Knuth's "List merge sort" (Algorithm 5.2.4L from Vol.3 of TAOCP, 2nd ed.). I'll add some comments at the end, but here's a summary:
On random input, it runs a bit faster than Simon Tatham's code (see Dave Gamble's non-recursive answer, with a link) but a bit slower than Dave Gamble's recursive code. It's harder to understand than either. At least in my implementation, it requires each element to have TWO pointers to elements. (An alternative would be one pointer and a boolean flag.) So, it's probably not a useful approach. However, one distinctive point is that it runs very fast if the input has long stretches that are already sorted.
element *knuthsort(element *list)
{ /* This is my attempt at implementing Knuth's Algorithm 5.2.4L "List merge sort"
from Vol.3 of TAOCP, 2nd ed. */
element *p, *pnext, *q, *qnext, head1, head2, *s, *t;
if(!list) return NULL;
L1: /* This is the clever L1 from exercise 12, p.167, solution p.647. */
head1.next=list;
t=&head2;
for(p=list, pnext=p->next; pnext; p=pnext, pnext=p->next) {
if( cmp(p,pnext) > 0 ) { t->next=NULL; t->spare=pnext; t=p; }
}
t->next=NULL; t->spare=NULL; p->spare=NULL;
head2.next=head2.spare;
L2: /* begin a new pass: */
t=&head2;
q=t->next;
if(!q) return head1.next;
s=&head1;
p=s->next;
L3: /* compare: */
if( cmp(p,q) > 0 ) goto L6;
L4: /* add p onto the current end, s: */
if(s->next) s->next=p; else s->spare=p;
s=p;
if(p->next) { p=p->next; goto L3; }
else p=p->spare;
L5: /* complete the sublist by adding q and all its successors: */
s->next=q; s=t;
for(qnext=q->next; qnext; q=qnext, qnext=q->next);
t=q; q=q->spare;
goto L8;
L6: /* add q onto the current end, s: */
if(s->next) s->next=q; else s->spare=q;
s=q;
if(q->next) { q=q->next; goto L3; }
else q=q->spare;
L7: /* complete the sublist by adding p and all its successors: */
s->next=p;
s=t;
for(pnext=p->next; pnext; p=pnext, pnext=p->next);
t=p; p=p->spare;
L8: /* is this end of the pass? */
if(q) goto L3;
if(s->next) s->next=p; else s->spare=p;
t->next=NULL; t->spare=NULL;
goto L2;
}
There's a non-recursive linked-list mergesort in mono eglib.
The basic idea is that the control-loop for the various merges parallels the bitwise-increment of a binary integer. There are O(n) merges to "insert" n nodes into the merge tree, and the rank of those merges corresponds to the binary digit that gets incremented. Using this analogy, only O(log n) nodes of the merge-tree need to be materialized into a temporary holding array.
A tested, working C++ version of single linked list, based on the highest voted answer.
singlelinkedlist.h:
#pragma once
#include <stdexcept>
#include <iostream>
#include <initializer_list>
namespace ythlearn{
template<typename T>
class Linkedlist{
public:
class Node{
public:
Node* next;
T elem;
};
Node head;
int _size;
public:
Linkedlist(){
head.next = nullptr;
_size = 0;
}
Linkedlist(std::initializer_list<T> init_list){
head.next = nullptr;
_size = 0;
for(auto s = init_list.begin(); s!=init_list.end(); s++){
push_left(*s);
}
}
int size(){
return _size;
}
bool isEmpty(){
return size() == 0;
}
bool isSorted(){
Node* n_ptr = head.next;
while(n_ptr->next != nullptr){
if(n_ptr->elem > n_ptr->next->elem)
return false;
n_ptr = n_ptr->next;
}
return true;
}
Linkedlist& push_left(T elem){
Node* n = new Node;
n->elem = elem;
n->next = head.next;
head.next = n;
++_size;
return *this;
}
void print(){
Node* loopPtr = head.next;
while(loopPtr != nullptr){
std::cout << loopPtr->elem << " ";
loopPtr = loopPtr->next;
}
std::cout << std::endl;
}
void call_merge(){
head.next = merge_sort(head.next);
}
Node* merge_sort(Node* n){
if(n == nullptr || n->next == nullptr)
return n;
Node* middle = getMiddle(n);
Node* left_head = n;
Node* right_head = middle->next;
middle->next = nullptr;
return merge(merge_sort(left_head), merge_sort(right_head));
}
Node* getMiddle(Node* n){
if(n == nullptr)
return n;
Node* slow, *fast;
slow = fast = n;
while(fast->next != nullptr && fast->next->next != nullptr){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
Node* merge(Node* a, Node* b){
Node dummyHead;
Node* current = &dummyHead;
while(a != nullptr && b != nullptr){
if(a->elem < b->elem){
current->next = a;
a = a->next;
}else{
current->next = b;
b = b->next;
}
current = current->next;
}
current->next = (a == nullptr) ? b : a;
return dummyHead.next;
}
Linkedlist(const Linkedlist&) = delete;
Linkedlist& operator=(const Linkedlist&) const = delete;
~Linkedlist(){
Node* node_to_delete;
Node* ptr = head.next;
while(ptr != nullptr){
node_to_delete = ptr;
ptr = ptr->next;
delete node_to_delete;
}
}
};
}
main.cpp:
#include <iostream>
#include <cassert>
#include "singlelinkedlist.h"
using namespace std;
using namespace ythlearn;
int main(){
Linkedlist<int> l = {3,6,-5,222,495,-129,0};
l.print();
l.call_merge();
l.print();
assert(l.isSorted());
return 0;
}
Simplest Java Implementation:
Time Complexity: O(nLogn) n = number of nodes. Each iteration through the linked list doubles the size of the sorted smaller linked lists. For example, after the first iteration, the linked list will be sorted into two halves. After the second iteration, the linked list will be sorted into four halves. It will keep sorting up to the size of the linked list. This will take O(logn) doublings of the small linked lists' sizes to reach the original linked list size. The n in nlogn is there because each iteration of the linked list will take time proportional to the number of nodes in the originial linked list.
class Node {
int data;
Node next;
Node(int d) {
data = d;
}
}
class LinkedList {
Node head;
public Node mergesort(Node head) {
if(head == null || head.next == null) return head;
Node middle = middle(head), middle_next = middle.next;
middle.next = null;
Node left = mergesort(head), right = mergesort(middle_next), node = merge(left, right);
return node;
}
public Node merge(Node first, Node second) {
Node node = null;
if (first == null) return second;
else if (second == null) return first;
else if (first.data <= second.data) {
node = first;
node.next = merge(first.next, second);
} else {
node = second;
node.next = merge(first, second.next);
}
return node;
}
public Node middle(Node head) {
if (head == null) return head;
Node second = head, first = head.next;
while(first != null) {
first = first.next;
if (first != null) {
second = second.next;
first = first.next;
}
}
return second;
}
}
Another example of a non-recursive merge sort for linked lists, where the functions are not part of a class. This example code and HP / Microsoft std::list::sort both use the same basic algorithm. A bottom up, non-recursive, merge sort that uses a small (26 to 32) array of pointers to the first nodes of a list, where array[i] is either 0 or points to a list of size 2 to the power i. On my system, Intel 2600K 3.4ghz, it can sort 4 million nodes with 32 bit unsigned integers as data in about 1 second.
typedef struct NODE_{
struct NODE_ * next;
uint32_t data;
}NODE;
NODE * MergeLists(NODE *, NODE *); /* prototype */
/* sort a list using array of pointers to list */
/* aList[i] == NULL or ptr to list with 2^i nodes */
#define NUMLISTS 32 /* number of lists */
NODE * SortList(NODE *pList)
{
NODE * aList[NUMLISTS]; /* array of lists */
NODE * pNode;
NODE * pNext;
int i;
if(pList == NULL) /* check for empty list */
return NULL;
for(i = 0; i < NUMLISTS; i++) /* init array */
aList[i] = NULL;
pNode = pList; /* merge nodes into array */
while(pNode != NULL){
pNext = pNode->next;
pNode->next = NULL;
for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
pNode = MergeLists(aList[i], pNode);
aList[i] = NULL;
}
if(i == NUMLISTS) /* don't go beyond end of array */
i--;
aList[i] = pNode;
pNode = pNext;
}
pNode = NULL; /* merge array into one list */
for(i = 0; i < NUMLISTS; i++)
pNode = MergeLists(aList[i], pNode);
return pNode;
}
/* merge two already sorted lists */
/* compare uses pSrc2 < pSrc1 to follow the STL rule */
/* of only using < and not <= */
NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
if(pSrc1 == NULL)
return pSrc2;
if(pSrc2 == NULL)
return pSrc1;
while(1){
if(pSrc2->data < pSrc1->data){ /* if src2 < src1 */
*ppDst = pSrc2;
pSrc2 = *(ppDst = &(pSrc2->next));
if(pSrc2 == NULL){
*ppDst = pSrc1;
break;
}
} else { /* src1 <= src2 */
*ppDst = pSrc1;
pSrc1 = *(ppDst = &(pSrc1->next));
if(pSrc1 == NULL){
*ppDst = pSrc2;
break;
}
}
}
return pDst;
}
Visual Studio 2015 changed std::list::sort to be based on iterators instead of lists, and also changed to a top down merge sort, which requires the overhead of scanning. I initially assumed that the switch to top down was needed to work with the iterators, but when it was asked about again, I investigated this and determined that the switch to the slower top down method was not needed, and bottom up could be implemented using the same iterator based logic. The answer in this link explains this and provide a stand-alone example as well as a replacement for VS2019's std::list::sort() in the include file "list".
`std::list<>::sort()` - why the sudden switch to top-down strategy?
This is the entire Piece of code which shows how we can create linklist in java and sort it using Merge sort. I am creating node in MergeNode class and there is another class MergesortLinklist where there is divide and merge logic.
class MergeNode {
Object value;
MergeNode next;
MergeNode(Object val) {
value = val;
next = null;
}
MergeNode() {
value = null;
next = null;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public MergeNode getNext() {
return next;
}
public void setNext(MergeNode next) {
this.next = next;
}
#Override
public String toString() {
return "MergeNode [value=" + value + ", next=" + next + "]";
}
}
public class MergesortLinkList {
MergeNode head;
static int totalnode;
public MergeNode getHead() {
return head;
}
public void setHead(MergeNode head) {
this.head = head;
}
MergeNode add(int i) {
// TODO Auto-generated method stub
if (head == null) {
head = new MergeNode(i);
// System.out.println("head value is "+head);
return head;
}
MergeNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = new MergeNode(i);
return head;
}
MergeNode mergesort(MergeNode nl1) {
// TODO Auto-generated method stub
if (nl1.next == null) {
return nl1;
}
int counter = 0;
MergeNode temp = nl1;
while (temp != null) {
counter++;
temp = temp.next;
}
System.out.println("total nodes " + counter);
int middle = (counter - 1) / 2;
temp = nl1;
MergeNode left = nl1, right = nl1;
int leftindex = 0, rightindex = 0;
if (middle == leftindex) {
right = left.next;
}
while (leftindex < middle) {
leftindex++;
left = left.next;
right = left.next;
}
left.next = null;
left = nl1;
System.out.println(left.toString());
System.out.println(right.toString());
MergeNode p1 = mergesort(left);
MergeNode p2 = mergesort(right);
MergeNode node = merge(p1, p2);
return node;
}
MergeNode merge(MergeNode p1, MergeNode p2) {
// TODO Auto-generated method stub
MergeNode L = p1;
MergeNode R = p2;
int Lcount = 0, Rcount = 0;
MergeNode tempnode = null;
while (L != null && R != null) {
int val1 = (int) L.value;
int val2 = (int) R.value;
if (val1 > val2) {
if (tempnode == null) {
tempnode = new MergeNode(val2);
R = R.next;
} else {
MergeNode store = tempnode;
while (store.next != null) {
store = store.next;
}
store.next = new MergeNode(val2);
R = R.next;
}
} else {
if (tempnode == null) {
tempnode = new MergeNode(val1);
L = L.next;
} else {
MergeNode store = tempnode;
while (store.next != null) {
store = store.next;
}
store.next = new MergeNode(val1);
L = L.next;
}
}
}
MergeNode handle = tempnode;
while (L != null) {
while (handle.next != null) {
handle = handle.next;
}
handle.next = L;
L = null;
}
// Copy remaining elements of L[] if any
while (R != null) {
while (handle.next != null) {
handle = handle.next;
}
handle.next = R;
R = null;
}
System.out.println("----------------sorted value-----------");
System.out.println(tempnode.toString());
return tempnode;
}
public static void main(String[] args) {
MergesortLinkList objsort = new MergesortLinkList();
MergeNode n1 = objsort.add(9);
MergeNode n2 = objsort.add(7);
MergeNode n3 = objsort.add(6);
MergeNode n4 = objsort.add(87);
MergeNode n5 = objsort.add(16);
MergeNode n6 = objsort.add(81);
MergeNode n7 = objsort.add(21);
MergeNode n8 = objsort.add(16);
MergeNode n9 = objsort.add(99);
MergeNode n10 = objsort.add(31);
MergeNode val = objsort.mergesort(n1);
System.out.println("===============sorted values=====================");
while (val != null) {
System.out.println(" value is " + val.value);
val = val.next;
}
}
}
I don't see any C++ solutions posted here. So, here it goes. Hope it helps someone.
class Solution {
public:
ListNode *merge(ListNode *left, ListNode *right){
ListNode *head = NULL, *temp = NULL;
// Find which one is the head node for the merged list
if(left->val <= right->val){
head = left, temp = left;
left = left->next;
}
else{
head = right, temp = right;
right = right->next;
}
while(left && right){
if(left->val <= right->val){
temp->next = left;
temp = left;
left = left->next;
}
else{
temp->next = right;
temp = right;
right = right->next;
}
}
// If some elements still left in the left or the right list
if(left)
temp->next = left;
if(right)
temp->next = right;
return head;
}
ListNode* sortList(ListNode* head){
if(!head || !head->next)
return head;
// Find the length of the list
int length = 0;
ListNode *temp = head;
while(temp){
length++;
temp = temp->next;
}
// Reset temp
temp = head;
// Store half of it in left and the other half in right
// Create two lists and sort them
ListNode *left = temp, *prev = NULL;
int i = 0, mid = length / 2;
// Left list
while(i < mid){
prev = temp;
temp = temp->next;
i++;
}
// The end of the left list should point to NULL
if(prev)
prev->next = NULL;
// Right list
ListNode *right = temp;
// Sort left list
ListNode *sortedLeft = sortList(left);
// Sort right list
ListNode *sortedRight = sortList(right);
// Merge them
ListNode *sortedList = merge(sortedLeft, sortedRight);
return sortedList;
}
};
Here is the Java Implementation of Merge Sort on Linked List:
Time Complexity: O(n.logn)
Space Complexity: O(1) - Merge sort implementation on Linked List avoids the O(n) auxiliary storage cost normally associated with the
algorithm
class Solution
{
public ListNode mergeSortList(ListNode head)
{
if(head == null || head.next == null)
return head;
ListNode mid = getMid(head), second_head = mid.next; mid.next = null;
return merge(mergeSortList(head), mergeSortList(second_head));
}
private ListNode merge(ListNode head1, ListNode head2)
{
ListNode result = new ListNode(0), current = result;
while(head1 != null && head2 != null)
{
if(head1.val < head2.val)
{
current.next = head1;
head1 = head1.next;
}
else
{
current.next = head2;
head2 = head2.next;
}
current = current.next;
}
if(head1 != null) current.next = head1;
if(head2 != null) current.next = head2;
return result.next;
}
private ListNode getMid(ListNode head)
{
ListNode slow = head, fast = head.next;
while(fast != null && fast.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
Hey I know that this is a bit late an answer but got a fast simple one.
The code is in F# but will goes in any language. Since this is an uncommen language of the ML family, I'll give some point to enhance the readability.
F# are nesting done by tabulating. the last line of code in a function (nested part) are the return value. (x, y) is a tuple, x::xs is a list of the head x and tail xs (where xs can be empty), |> take the result of last line an pipe it as argument to the expression right of it (readability enhancing) and last (fun args -> some expression) are a lambda function.
// split the list into a singleton list
let split list = List.map (fun x -> [x]) lst
// takes to list and merge them into a sorted list
let sort lst1 lst2 =
// nested function to hide accumulator
let rec s acc pair =
match pair with
// empty list case, return the sorted list
| [], [] -> List.rev acc
| xs, [] | [], xs ->
// one empty list case,
// append the rest of xs onto acc and return the sorted list
List.fold (fun ys y -> y :: ys) acc xs
|> List.rev
// general case
| x::xs, y::ys ->
match x < y with
| true -> // cons x onto the accumulator
s (x::acc) (xs,y::ys)
| _ ->
// cons y onto the accumulator
s (y::acc) (x::xs,ys)
s [] (lst1, lst2)
let msort lst =
let rec merge acc lst =
match lst with
| [] ->
match acc with
| [] -> [] // empty list case
| _ -> merge [] acc
| x :: [] -> // single list case (x is a list)
match acc with
| [] -> x // since acc are empty there are only x left, hence x are the sorted list.
| _ -> merge [] (x::acc) // still need merging.
| x1 :: x2 :: xs ->
// merge the lists x1 and x2 and add them to the acummulator. recursiv call
merge (sort x1 x2 :: acc) xs
// return part
split list // expand to singleton list list
|> merge [] // merge and sort recursively.
It is important to notice that this is fully tail recursive so no possibility of stack overflow, and by first expanding the list to a singleton list list in one go we, lower the constant factor on the worst cost. Since merge are working on list of list, we can recursively merge and sort the inner list until we get to the fix point where all inner list are sorted into one list and then we return that list, hence collapsing from a list list to a list again.
Here is the solution using Swift Programming Language.
//Main MergeSort Function
func mergeSort(head: Node?) -> Node? {
guard let head = head else { return nil }
guard let _ = head.next else { return head }
let middle = getMiddle(head: head)
let left = head
let right = middle.next
middle.next = nil
return merge(left: mergeSort(head: left), right: mergeSort(head: right))
}
//Merge Function
func merge(left: Node?, right: Node?) -> Node? {
guard let left = left, let right = right else { return nil}
let dummyHead: Node = Node(value: 0)
var current: Node? = dummyHead
var currentLeft: Node? = left
var currentRight: Node? = right
while currentLeft != nil && currentRight != nil {
if currentLeft!.value < currentRight!.value {
current?.next = currentLeft
currentLeft = currentLeft!.next
} else {
current?.next = currentRight
currentRight = currentRight!.next
}
current = current?.next
}
if currentLeft != nil {
current?.next = currentLeft
}
if currentRight != nil {
current?.next = currentRight
}
return dummyHead.next!
}
And here are the Node Class & getMiddle Method
class Node {
//Node Class which takes Integers as value
var value: Int
var next: Node?
init(value: Int) {
self.value = value
}
}
func getMiddle(head: Node) -> Node {
guard let nextNode = head.next else { return head }
var slow: Node = head
var fast: Node? = head
while fast?.next?.next != nil {
slow = slow.next!
fast = fast!.next?.next
}
return slow
}
public int[] msort(int[] a) {
if (a.Length > 1) {
int min = a.Length / 2;
int max = min;
int[] b = new int[min];
int[] c = new int[max]; // dividing main array into two half arrays
for (int i = 0; i < min; i++) {
b[i] = a[i];
}
for (int i = min; i < min + max; i++) {
c[i - min] = a[i];
}
b = msort(b);
c = msort(c);
int x = 0;
int y = 0;
int z = 0;
while (b.Length != y && c.Length != z) {
if (b[y] < c[z]) {
a[x] = b[y];
//r--
x++;
y++;
} else {
a[x] = c[z];
x++;
z++;
}
}
while (b.Length != y) {
a[x] = b[y];
x++;
y++;
}
while (c.Length != z) {
a[x] = c[z];
x++;
z++;
}
}
return a;
}