Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to sort a stack using merge sort?

A stack can be implemented as a linked list. Linked lists can be sorted using merge sort: O(n log n) time O(n) space

It makes sense to be able to sort a stack using merge sort.

If that's the case, what would the code look like?

(after a quick search on the web, I only found brute force algorithms O(n^2))

like image 638
Raul Avatar asked Feb 21 '14 12:02

Raul


People also ask

Can a stack be sorted?

You are given a stack of integers, write a program to sort it. You could use another stack if needed. The top of the stack must point to the smallest element. The stack must be sorted in increasing order from the top of the stack to its bottom.

How many operations does merge sort take?

Mergesort has two steps: merging and sorting. The algorithm uses a divide-and-conquer approach to merge and sort a list. Divide and conquer is a technique used for breaking algorithms down into subproblems, solving the subproblems, and then combining the results back together to solve the original problem.


2 Answers

Yes, we can. The trick is understanding that when the stack is sorted, the head is the largest element - and we want to iterate it from lower to higher We can reverse a stack however in O(n).

reverse(stack):
   s <- new stack
   while stack.isEmpty() == false:
       s.push(stack.pop)
   return s

Now, using it, and assuming you can use size() as well, it is fairly easy to implement and is a standard for most stack implementation - we can implement a merge sort:

Pseudo code:

mergeSort(stack):
   if stack.isEmpty():
       return stack
   s1 <- new stack
   s2 <- new stack
   //   O(n):
   while s1.size() < stack.size():
        s1.push(stack.pop())
   while (stack.isEmpty() == false):
        s2.push(stack.pop())           
   mergeSort(s1) //half the size of stack
   mergeSort(s2) //half the size of stack
   //head of s1 and s2 is the largest element
   s1 <- s1.reverse() //easily implemented in O(n)
   s2 <- s2.reverse()
   //now head of s1 and s2 is the smallest element
   while (s1.isEmpty() == false and s2.isEmpty() == false):
        if (s1.peek() < s2.peek()):
            stack.push(s1.pop())
         else:
            stack.push(s2.pop())
   //the 'tail' of one stack:
   while (s1.isEmpty() == false):
         stack.push(s1.pop())
   while (s2.isEmpty() == false):
         stack.push(s2.pop())
   //head is the largest, stacks are sorted
   return stack

Correctness:
Base: The stop clause is an empty stack, which is sorted.
Hypothesis: s1 and s2 are sorted.
Step: After reversing, s1 and s2 are basically traversed in the order of lower->higher, in sorted area when taking off elements using the pop() method. Since we always insert the smaller element from each stack, and we are traversing each stack from low to high - we get that the resulting stack is in order.

Complexity:
Excluding recursive calls, each step is O(stack.size()) = O(n). This is the same behavior as regular merge sort, and the rest of the complexity follows the same steps of original merge sort to get O(nlogn).

like image 94
amit Avatar answered Oct 05 '22 13:10

amit


maybe i miss the point but i would do it this way:

void mergesortStack(Stack input) {
    if (input.isEmpty()) {
        return;
    }

    Stack stackLeft = new Stack();
    Stack stackRight = new Stack();

    // split
    while (!input.isEmpty()) {
        stackLeft.push(input.pop());
        if (!input.isEmpty()) {
            stackRight.push(input.pop());
        }
    }

    // recurse
    if (!stackLeft.isEmpty() && !stackRight.isEmpty()) {
        mergesortStack(stackLeft);
        mergesortStack(stackRight);
    }

    // merge
    Stack tmpStack = new Stack();
    while (!stackLeft.isEmpty() || !stackRight.isEmpty()) {
        if (stackLeft.isEmpty()) {
            tmpStack.push(stackRight.pop());
        } else if (stackRight.isEmpty()) {
            tmpStack.push(stackLeft.pop());
            // set an appropriate compare method
        } else if (stackLeft.peek().compareTo(stackRight.peek()) >= 0) {
            tmpStack.push(stackLeft.pop());
        } else {
            tmpStack.push(stackRight.pop());
        }
    }

    // reverse stack
    while (!tmpStack.isEmpty()) {
        input.push(tmpStack.pop());
    }
}
like image 28
Absurd-Mind Avatar answered Oct 05 '22 12:10

Absurd-Mind