Microsoft Interview Question


Country: India
Interview Type: In-Person




Comment hidden because of low score. Click to expand.
10
of 12 vote

Merge Sort

- Anonymous September 02, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

+1

- Deepak Garg September 02, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

The good news about using mergesort for linked lists is that it doesn't really require extra space like it does for arrays.

- eugene.yarovoi September 02, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I believe this is the best answer since the merge operation works well in a singly linked list

void mergesort_linkedlist(Node* before_start, Node* start, Node* end) {
  if (start == end) return; // sorted
  // Find middle node
  Node* before_middle = NULL;
  Node* middle = start;
  Node* curr = start;
  while (curr && curr != end) {
    curr = curr->next;
    if (curr) {
      curr = curr->next;
      before_middle = middle;
      middle = middle->next;
    }
  }
  // Sort both ranges
  mergesort_linkedlist(before_start, start, middle)
  mergesort_linekdlist(before_middle, middle, end);
  // Merge ranges
  Node* before_insert = before_start;
  Node* after_insert = start;
  Node* p2 = middle;
  while (!(p1 == middle && p2 == end)) {
    if (p2->val < after_insert->val || after_insert == middle) {
      Node* tmp = p2->next;
      before_insert->next = p2;
      p2->next = after_insert;
      before_insert = p2;
      p2 = tmp; 
    }
    else {
      before_insert = after_insert;
      after_insert = after_insert->next;
    }
  }
}

- Martin September 02, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

The algo above has many errors (typos and not only).
For example, 1) p1 is not initialized; 2) the first 'while' loop for 'middle' finding and the first recursive call form an infinite recursive in case of end == start->next; and etc..

- Aleksey.M September 21, 2012 | Flag
Comment hidden because of low score. Click to expand.
2
of 2 vote

Most people think you can't use quicksort. That is wrong. Quicksort works just fine. Simply scan through the list moving nodes with data value less than the pivot to a new list and nodes with data value greater than the pivot to another new list. Recursively sort the two new lists and then splice them together with the remains of the original list.

- Anonymous September 02, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

It's true, there's no reason you couldn't use quicksort.

- eugene.yarovoi September 04, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

I dont understand why merge sort is cheaper than the insertion or selection or bubble sort in this situation. Since finding the mid of the list requires O(n)

- evan September 04, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

So, the order of complexity is >= O(n^2) with merge sort, which is also the case for insertion sort. So merge sort is not better than insertion/selection/bubble sort.

- Anonymous March 18, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

int condition=0,count1=0,count2=0;
node *q;
node *p;
node*r;
node* merge(node* l1,node *l2,int n,int m)
{
if(l1!=NULL&&((count1<n&&count2==m)||((l1->data<=l2->data)&&count1<n)))
{
// cout<<"fdnhrn";
if(condition==0)
{
condition=1;
p=l1;
l1=l1->next;
q=p;
count1++;
}
else
{
// cout<<l1->data<<" "<<q->data;
q->next=l1;
l1=l1->next;
q=q->next;
count1++;
}
}
else if(l2!=NULL&&((count2<m&&count1==n)||(l1->data>l2->data&&count2<m)))
{
// cout<<"what";
if(condition==0)
{
condition=1;
p=l2;
l2=l2->next;
q=p;
count2++;
}
else
{
q->next=l2;
l2=l2->next;
q=q->next;
count2++;
}
}
if(count1==n&&count2==m)
{
q->next=NULL;
node*a1=p;
return p;
}

else
{
node*a1=p;
p=merge(l1,l2,n,m);
}
return p;
}
node* mergesort(node* q[],int start,int end,int n)
{
//cout<<q[0]->data<< " "<<q[2]->data;
node* l1=NULL;
node *l2=NULL;
if((n/2)>1)
l1=mergesort(q,start,(n/2),(n/2));
if((n+1)/2>1)
l2=mergesort(q,start+(n)/2,end,(n+1)/2);
if(n/2==1)
l1= q[start-1];
if((n+1)/2==1)
l2= q[start+(n)/2-1];
condition=0;
count1=0;count2=0;
node *a=merge(l1,l2,n/2,(n+1)/2);
node*a1=a;
return a;
}

- pankaj-iit roorkee September 13, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

void MergeSort(Node **before, Node **start, Node **end)
	{
		if(!*start || !*end) return; // in case of NULL
		if(*start == *end) return;  // there is only one element in the list

		if((*start)->pNext == *end) // there are two elements in the list
		{
			Node *tmp = NULL;
			if((*start)->iData > (*end)->iData) // exchange them if needed
			{
				tmp = *start; // it's important to change data by the given addresses
				(*before)->pNext = (*end);
				*start = *end;
				*end = tmp;
				(*end)->pNext = (*start)->pNext;
				(*start)->pNext = *end;
			}
			return;
		}
		Node *pFast = *start, *middle = *start;
		if(!*start || !(*start)->pNext || !(*start)->pNext->pNext)
		{
			middle = *start;
		}
		else
		{
			while(pFast && pFast != (*end)) // finding the middle
			{
				pFast = pFast->pNext;
				if(pFast)
				{
					pFast = pFast->pNext;
					if(pFast)
					{
						middle = middle->pNext;
					}
				}
			}
		}
		MergeSort(before, start, &middle); // recursive call for the first part of the list
		MergeSort(&middle, &(middle->pNext), end); // recursive call for the last part of the list

		Node *pNewLast = NULL, *pLefLast = *start, *pRightLast = middle->pNext;
		if(pLefLast->iData <= pRightLast->iData) // set the last elemnt for the new merged list
		{								  // At the moment it is the fisrt elemnt for the
			pNewLast = pLefLast;			  //  new merged list
			pLefLast = pLefLast->pNext;
		}
		else
		{
			middle->pNext = pRightLast->pNext;
			pNewLast = pRightLast;
			(*before)->pNext = pRightLast;
			pRightLast = pRightLast->pNext;
		}
		(*start) = (*before)->pNext; // it's important to set new data by the adress of the 'start' element
		while(pLefLast != middle->pNext && pRightLast != NULL && pRightLast != (*end)->pNext)
		{                             // cycle to merge two sorted lists
			if(pLefLast->iData <= pRightLast->iData)
			{
				pNewLast->pNext = pLefLast;
				pNewLast = pNewLast->pNext;
				pLefLast = pLefLast->pNext;
			}
			else
			{
				middle->pNext = pRightLast->pNext;
				pNewLast->pNext = pRightLast;
				pNewLast = pNewLast->pNext;
				pRightLast = pRightLast->pNext;
			}
		}
		if(pLefLast == middle->pNext) // merging the remainders if needed
		{
			pNewLast->pNext = pRightLast;
		}
		else if((pRightLast == (*end)->pNext)||(pRightLast == NULL))
		{                             // merging the remainders if needed
			pNewLast->pNext = pLefLast;
			(*end) = middle;  //it's important to set new data by the adress of the 'end' element
		}
	}


        void sort(){
		Node *pEnd = NULL, *pAxPtr = new Node;

		pEnd = LList->pHead;
		while(pEnd->pNext)pEnd = pEnd->pNext;
		pAxPtr->pNext = LList->pHead;
		LList->MergeSort(&pAxPtr, &(LList->pHead), &pEnd);
		LList->pHead = pAxPtr->pNext;
                delete pAxPtr;
       }

- Aleksey.M September 23, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

/* sorts the linked list by changing next pointers (not data) */
void MergeSort(struct node** headRef)
{
struct node* head = *headRef;
struct node* a;
struct node* b;

/* Base case -- length 0 or 1 */
if ((head == NULL) || (head->next == NULL))
{
return;
}

/* Split head into 'a' and 'b' sublists */
FrontBackSplit(head, &a, &b);

/* Recursively sort the sublists */
MergeSort(&a);
MergeSort(&b);

/* answer = merge the two sorted lists together */
*headRef = SortedMerge(a, b);
}

struct node* SortedMerge(struct node* a, struct node* b)
{
struct node* result = NULL;

/* Base cases */
if (a == NULL)
return(b);
else if (b==NULL)
return(a);

/* Pick either a or b, and recur */
if (a->data <= b->data)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return(result);
}

/* UTILITY FUNCTIONS */
/* Split the nodes of the given list into front and back halves,
and return the two lists using the reference parameters.
If the length is odd, the extra node should go in the front list.
Uses the fast/slow pointer strategy. */
void FrontBackSplit(struct node* source,
struct node** frontRef, struct node** backRef)
{
struct node* fast;
struct node* slow;
if (source==NULL || source->next==NULL)
{
/* length < 2 cases */
*frontRef = source;
*backRef = NULL;
}
else
{
slow = source;
fast = source->next;

/* Advance 'fast' two nodes, and advance 'slow' one node */
while (fast != NULL)
{
fast = fast->next;
if (fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
}

/* 'slow' is before the midpoint in the list, so split it in two
at that point. */
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
}

Time Complexity: O(nLogn)

- shivam kapoor September 28, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 3 vote

insertion sort

- dev September 02, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 3 vote

insertion sort

- arul September 02, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 3 vote

Yes the answer is Insertion Sort... For people who think otherwise, please take a look a MIT open course ware Algorithm videos on YouTube...

- abilash.s.90 September 03, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

No one's denying that it's possible to use insertion sort. But it's not the most efficient algorithm here.

- eugene.yarovoi September 03, 2012 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

HeapSort maybe... First form the heap of the link-list using bubble_down() method for elements i = 1 to N (done is O(NLog(N)) time).
Then, extract mean (done in O(1) time) and use bubble_down() again to restore heap.
Runtime complexity is O(NLog(N)) and memory required is O(N). HeapSort is best, as far as Sorting is considered.

- Deval September 03, 2012 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Heapsort is difficult to do on something that doesn't have random access like a linked list. And even if you could do it, why would it be the best?

- eugene.yarovoi September 03, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Yes! Missed the point that Link-list can have random access. Merge Sort will be best suited.

- Deval September 03, 2012 | Flag


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More