Sort with two stacks

## Problem description

Given an array that is initially stored in one stack, sort it with one additional stack (total 2 stacks).

After sorting the original stack should contain the sorted integers and from top to bottom the integers are sorted in ascending order.

Assumptions
* The given stack is not null.
* There can be duplicated numbers in the give stack.

Example 1
* **Input**: [6, 2, 5, 1, 3, 8, 7, 4]
* **Output**: [1, 2, 3, 4, 5, 6, 7, 8]

Example 2
* **Input**: [4, 2, 1, 5, 1, 3, 2, 5]
* **Output**: [1, 1, 2, 2, 3, 4, 5, 5]

Requirements
* No additional memory, time complexity = **O(n2)**.

## Analysis

First we should note some important properties of transferring data from one stack to another:

* If we transfer the content from stack 1 to stack 2 (either partially or completely), then the transferred elements will appear in stack 2 in the *reverse order* of they were in stack 1.
* Doing a transfer takes O(n) time complexity, where *n* is the number of elements to be transferred.

Now, in this problem:

* **Stack 1** is the *input stack* (and the *output stack*);
* And we are asked to use **stack 2** as a *temporary stack*.

So we can consider putting data in descending sorted order in stack 2 (the temporary stack), and then transfer everything back to stack 1 (the output stack). This requires us to find the *max value* in stack 1 each time.

In addition, stack 2 is split into two parts for the two purposes:

* The left hand side stores the elements that are already sorted in descending order.
* The right hand side serves as the free space to temporarily store the elements moved from stack 1.

Note
Let stack 1 has *n* elements, i.e. the total elements to be sorted.
Then, whenever we have *m* elements sorted on the left of stack 2, the stack 1 will have *n-m* elements unsorted, and also stack 2 has *n-m* free spaces on the right.
Hence, the *n-m* spots in stack 2 can be used as the free space to process the remaining elements in stack 1.
So our approach to meet the requirements is as follows:

1. Initially, the number of sorted elements is 0.
2. For each iteration:
	1. Locate the maximum value and its index in stack 1. Save them to a helper variable.
	2. Transfer all elements after the maximum value index (*not including the maximum value index*) in stack 1 to stack 2.
	3. Then, at this moment, the last element in stack 1 is the maximum element of stack 1. Pop this element from stack 1.
	4. Transfer back all the unsorted values from stack 2 to stack 1. Now stack 1 has everything from last step except the popped maximum element.
	5. Put this maximum element after the currently sorted elements in stack 2. Increase the number of sorted element by 1.
3. Repeat the iteration above, until all elements in stack 1 are sorted in stack 2. Now stack 2 has all the elements in descending order.
4. Transfer all elements from stack 2 back to stack 1. Then all elements in stack 1 are sorted in ascending order.

### Complexity analysis

#### Time complexity

* For *n* input elements, we have *n* iterations.
* Each iteration requires the following steps. In the *m*-th iteration:
	1. Find the max element in stack 1. The time complexity is O(m).
	2. Transfer all elements after the index of max element in stack 1 to stack 2. The time complexity is O(m).
	3. Pop the max element from stack 1, and save it to a temporary variable. The time complexity is O(1).
	4. Put back all unsorted elements from stack 2 to stack 1. The time complexity is O(m-1) = O(m).
	5. Put the max element into stack 2. The time complexity is O(1).

So the total time complexity =

O
(
n
)
O
(
n
−
1
)
O
(
n
−
2
)
⋯
O
(
1
# )
O
(

(
n
1
)
n

2

# )
O
(

n
2

)

{\displaystyle O(n) + O(n-1) + O(n-2) + \dots + O(1) = O(\frac{(n+1)n}{2}) = O(n^2)}

. This satisfies the problem requirement.

#### Space complexity

Stack
We only need to store the temporary stack (stack 2), max value, and max index. The space complexity on memory stack is O(1).
Heap
We only have allocated the temporary stack on the heap.
For the input stack with *n* elements, the temporary stack will grow to at most size *n*.
This means that the space complexity on the heap is *O(n)*.
The total space complexity is **O(n)**.

## Solution codes

### Java

```
public class Solution {
 private static class MaxHelper {
 public int index;
 public int value;

 public MaxHelper() {
 index = -1;
 value = Integer.MIN\_VALUE;
 }
 }

 // find max index and max value of the stack
 // assumption: stack is not null
 private static MaxHelper findMax(LinkedList<Integer> stack, MaxHelper maxHelper) {
 if (maxHelper == null) {
 maxHelper = new MaxHelper();
 }

 int currentMax = Integer.MIN\_VALUE, currentMaxIndex = 0;
 int i = 0;
 for (int item: stack) {
 if (item >= currentMax) {
 currentMaxIndex = i;
 currentMax = item;
 }
 ++i;
 }
 maxHelper.index = currentMaxIndex;
 maxHelper.value = currentMax;
 return maxHelper;
 }

 // transfer all elements from s1 to s2
 // then s2 have elements in reverse order of s1
 // return s2
 // assumption: s1 and s2 are both not null
 private LinkedList<Integer> transferAll(LinkedList<Integer> s1, LinkedList<Integer> s2) {
 while (!s1.isEmpty()) {
 s2.offerLast(s1.pollLast());
 }
 return s2;
 }

 public void sort(LinkedList<Integer> s1) {
 // Write your solution here.
 if (s1 == null) {
 return;
 }

 final int totalNum = s1.size();
 if (totalNum < 2) {
 return;
 }

 // use s2 as sorted stack (left side, descending) + buffer stack (right side)
 LinkedList<Integer> s2 = new LinkedList();
 MaxHelper maxHelper = new MaxHelper();
 int numSorted = 0;
 while (numSorted < totalNum) {
 // find max value and max index
 maxHelper = findMax(s1, maxHelper);
 // pull all elements including and after max index to s2
 for (int j = s1.size() - 1; j > maxHelper.index; --j) {
 s2.offerLast(s1.pollLast());
 }
 // pop off max element from s1
 s1.pollLast();
 // pull all remaining elements back to s1
 for (int j = s2.size() - 1; j >= numSorted; --j) {
 s1.offerLast(s2.pollLast());
 }
 // put max element in s2
 s2.offerLast(maxHelper.value);
 ++numSorted;
 }
 // now s2 is in descending order
 // transfer all from s2 back to s1
 // so s1 is in ascending order
 transferAll(s2, s1);
 }
}

```

## External links

* Sort a stack using a temporary stack (Archive)