This is the Merge Sort code:
public class MergeSort {
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7};
System.out.println("Unsorted Array:");
printArray(arr);
mergeSort(arr, 0, arr.length - 1);
System.out.println("Sorted Array:");
printArray(arr);
}
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int middle = (left + right) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
public static void merge(int[] arr, int left, int middle, int right) {
int n1 = middle - left + 1;
int n2 = right - middle;
int[] leftArray = new int[n1];
int[] rightArray = new int[n2];
for (int i = 0; i < n1; i++) {
leftArray[i] = arr[left + i];
}
for (int i = 0; i < n2; i++) {
rightArray[i] = arr[middle + 1 + i];
}
int i = 0, j = 0;
int k = left;
while (i < n1 && j < n2) {
if (leftArray[i] <= rightArray[j]) {
arr[k] = leftArray[i];
i++;
} else {
arr[k] = rightArray[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = leftArray[i];
i++;
k++;
}
while (j < n2) {
arr[k] = rightArray[j];
j++;
k++;
}
}
public static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}
I am specifically looking at the mergeSort(int[] arr, int left, int right) function which recursively calls itself and divides the array using the middle index or m.
I am having trouble understanding how the stack will be formed since there are back to back two recursive statements and a call to the merge function.
For instance, if there is an int[] array = [5, 4, 6, 7, 8, 2, 1]
and r and l are array.length - 1 and 0 respectively, then the base condition is satisfied, m = 3 and the first recursive call is made which assigns m to right. Then the same recursive call is made until the base condition is not satisfied.Once the base condition is not satisfied, the second recursive call is made. I am not sure if the second recursive call is made side by side the first one and what that stack will look like, and in what order will merge be called on the 'subarrays'.
Please help by showing what the stack would look like for the aforementioned array and in what order will merge be called on them. Thank you!
It's immaterial how many recursive (or non-recursive) subcalls are made from a function as far as the stack is concerned. If a function has two recursive calls, the first recursive call must completely finish (i.e. clear the stack frames it created) before the second recursive call begins on a totally fresh "sub-stack" (if you will). Stacks can only push or pop, so it's not like the stack splits into two or anything like that.
As mentioned above, multiple recursive calls happen in series, not parallel or "side by side". The left subarray call chain runs, clears and then the right subarray chain takes its place on the stack, running and clearing.
Recursion isn't necessary to understand this. Consider the following pseudocode:
The stack will be:
[](initially empty)[foo](callfoo())[foo, bar](callbar()fromfoo(), pausingfoo())[foo](completebar(), returning control tofoo()momentarily)[foo, baz](callbaz()fromfoo(), pausingfoo())[foo](completebaz(), returning control tofoo())[](completefoo(), popping the last item from the call stack)So
barandbazwill never be on the stack at the same time.I'm not sure what you mean by "what order will
mergebe called on the subarrays", butmergeisn't called until both subarrays are sorted recursively and the calls spawned by the current call tomergeSortare completed.mergethen, well, merges the two subarrays into one sorted subarray, fulfillingmergeSort's obligation to its parent frame (sorting its subarray) and returning control to that parent frame, which is paused waiting for its child call to finish. Once it regains control, the parent call will then begin work on its right subchild or merge its sorted subarrays, depending on where its execution was blocked.Here's what the call stack would look like on an array with 6 elements, similar to yours (the whole array is passed through the calls, so that's always the same and can be ignored for the purposes of call stack visualization):
Another common way to visualize the calls is:
In this visualizer, the current stack grows left to right. You can determine the current stack by following the left-right thread, keeping in mind that previous calls on the same level are already popped, not running in parallel. Adding animation can help clarify the behavior: