Sorting algorithm (four)--merge sort and recursion

Source: Internet
Author: User

Basic ideas

Before we analyze the merge sort, let's take a look at the divide-and- conquer algorithm .

The basic idea of divide-and-conquer algorithm is to decompose a problem of size n into a small sub-problem of K, which is independent and the same nature as the original problem. The solution of the problem can be obtained by finding out the solution of the sub-problems.

General steps of the divide-and-conquer algorithm:

(1) Decomposition, the problem to be solved divided into a number of small-scale similar problems;

(2) solving, when sub-problem is divided into enough hours, with a relatively simple method to solve;

(3) Merging, according to the requirements of the original problem, the solution of sub-problem is composed of layers to form the solution of the original problem.

Merge sort is a typical application of divide-and-conquer algorithm.

The merge sort first cuts an unordered n-long array into n ordered subsequence (the sequence of only one data is considered ordered), then 22 merges, then the merged N/2 (or N/2 + 1) subsequence continues with 22 merges, and so on, a complete ordered array is obtained. The process is as follows:



Java implementation

The core idea of merge sorting is to merge two ordered arrays into another array, so you need to open up additional space .

The first step is to clarify the idea of merging. Suppose you now have two ordered arrays A and B, to merge the two into array C in an orderly manner. We use an example to deduce:


, the A array has four elements, the B array has six elements, first compares the first element in a, B, and the smaller one to the first of the C array, because the element is the smallest of all elements of A and B. In the above example, 7 is less than 23, so 7 is placed in C.

Then, compare 23 with the other elements in B, if less than 23, continue in order to C, if greater than 23, 23 into C.

23 after placing in C, use the 47 after 23 as the Datum element, and continue to compare with the other elements in B, repeating the above steps.

If the elements of an array have all been copied to C, then insert the remaining elements in the other array into C in turn. This concludes.

In accordance with the above ideas, in Java implementation:

/** * merge Arraya and arrayb into ARRAYC * @param arraya Array A * @param sizea the length of array A * @ param Arrayb Array b * @param Sizeb array B's length * @param arrayc auxiliary Merge sorted array */public static void merge (int [] Array A,int sizea, int [] arrayb,int sizeb, int [] arrayc) {int i=0,  j=0,k=0; As Arraya, Arrayb, ARRAYC, respectively, the subscript pointer while (i<sizea&& J<sizeb) {//Two arrays are not empty if (arraya[           I]<ARRAYB[J]) {//Put the smaller one in Arrayc arrayc[k++]= arraya[i++];          }else{arrayc[k++]= arrayb[j++];           }}//At the end of the loop, an array has been completely copied to ARRAYC, and another array with elements//followed by two while loops is used to process another non-empty array while (I<sizea) {        Arrayc[k++]= arraya[i++];       } while (J<sizeb) {arrayc[k++]= arraya[j++];       } for (intl=0;l<arrayc.length;l++) {//Prints the element System.out.print (arrayc[l]+ "\ T") in the new array; }   }

Before merging, there is one step that needs to be done in advance, that is, the decomposition of the array, which can be achieved by recursive method. Recursive(Recursive) is a common idea in algorithm design.

This completes the merge sort by first recursively decomposing the array and then merging the array.

The complete Java code is as follows:

public class Sort {private int [] array;   The array to be sorted public sort (int [] array) {this.array= array; }//Print the elements in the array in order public void display () {i=0;i<array.length;i++ (int) {System.out.print (array[i]+       "\ t");   } System.out.println (); }//merge sort public void MergeSort () {int[] workSpace = new int [array.length];//array for auxiliary sorting recursiveme   Rgesort (workspace,0,workspace.length-1); /** * Recursive Merge sort * @param workSpace array of auxiliary sorting * @param lowerbound to merge the smallest subscript of an array segment * @param upperbound to merge the maximum of the array segment Marked */private void Recursivemergesort (int [] Workspace,int lowerbound,int upperbound) {if (lowerbound== upp       Erbound) {//the segment has only one element, without ordering return;          }else{int mid = (lowerbound+upperbound)/2;    Recursivemergesort (Workspace,lowerbound,mid);  Recursivemergesort (Workspace,mid+1,upperbound) of the lower segment merge sort;          Merge (Workspace,lowerbound,mid,upperbound) for high-level segment merging; Display); }}/** * Merges two segments in an array of arrays, Lowerbound~mid is a low segment, Mid+1~upperbound is a high segment * @param workSpace an array of auxiliary merges, accommodating the merged element * @pa Ram Lowerbound The starting subscript of the merged segment * @param mid-midpoint subscript of the middle merge segment * @param the end subscript for the merged segment of the upperbound */private void merge (int [] Workspa  Ce,int lowerbound,int mid,int upperbound) {int lowbegin = lowerbound;           The starting subscript int lowend = Mid for the low segment;  The end subscript int highbegin = mid+1 of the low segment;  The starting subscript int highend = Upperbound of the high-level segment; The end subscript of the high segment int j = 0;  workspace subscript pointer int n = upperbound-lowerbound+1; Total number of merged elements while (Lowbegin<=lowend && highbegin<=highend) {if (array[lowbegin]<array[h           Ighbegin]) {//Put the smaller one in WorkSpace workspace[j++]= array[lowbegin++];           }else{workspace[j++]= array[highbegin++];        }} while (Lowbegin<=lowend) {workspace[j++]= array[lowbegin++]; } while (Highbegin<=highend) {workspace[j++]= array[highbegin++];       } for (j=0;j<n;j++) {//Copy the merged elements into the array array[lowerbound++]= workspace[j]; }         }}
Test with the following code:

int [] a ={6,2,7,4,8,1,5,3}; Sort sort = Newsort (a); Sort.mergesort ();

The printing results are as follows:



The order of merging is this: first, the initial array is divided into two parts, the lower segment is merged first, and then the high segment is merged. The lower segment and the high segment continue to decompose, and the low segment is decomposed into a more subdivided pair of low and high segments, and the high segment is also decomposed into a more segmented pair of low and high segments, and so on.

In the above example, the first step, merging is 6 and 2, the second step is to merge 7 and 4, the third part is the first two steps to merge the sub-segments [2,6] and [4,7]. At this point, the left half of the array (the low segment) is merged and then the right half (high segment) is merged.

So the fourth step is to merge the 8 and 1, the fourth merge is 5 and 3, the fifth step is to merge the first two steps into a good field [1,8] and [3,5]. At this point, the right half of the array is merged.

The final step is to merge the left half of the array [2,4,6,7] with the right half [1,3,5,8].

Merge sort ends.

In the beginning of the description of the merge sort, the first lie merge is to all the adjacent two elements after the end of the merge, not the next round of merging, not first merge the left half, and then merge the right half, but the order of execution of the program and our analysis of the merge sort of logic is inconsistent, so it is difficult to understand.

The following combination of code and legend to detailed analysis of the process of merging sorting.

A virtual machine stack (VM stack) is a memory model that describes the execution of Java methods, with each call to the method accompanied by a stack and a stack operation.

We want to sort the array as:

int [] a = {6,2,7,4,8,1,5,3}

When the main () method calls the MergeSort () method, the called method is pressed into the stack, and the program enters the MergeSort () method:

public void MergeSort () {       int[] workSpace = new int [array.length];//array recursivemergesort for auxiliary sorting       (workspace,0, workspace.length-1);   }
At this point, mergesort () also calls the Recursivemergesort (workspace,0,7) method, and the Recursivemergesort (workspace,0,7) method is also pressed into the stack, above MergeSort ().

The program then enters the Recursivemergesort (workspace,0,7) method:

if (lowerbound== upperbound) {  //the segment has only one element and no sort          return;       } else{          int mid = (lowerbound+upperbound)/2;          Recursivemergesort (workspace,lowerbound,mid);          Recursivemergesort (workspace,mid+1,upperbound) of the lower segment merge sort;          Merge (Workspace,lowerbound,mid,upperbound) for high-level segment merging;          Display ();        }

The Lowerbound parameter value is the 0,upperbound parameter value of 7 and does not meet the conditions of the lowerbound== upperbound, so the method enters the Else branch and then calls the method Recursivemergesort (WorkSpace, 0,3),

Recursivemergesort (workspace,0,3) is pressed into the stack with the following status:


However, Recursivemergesort (workspace,0,3) cannot return immediately, and it internally calls Recursivemergesort (workspace,0,1), Recursivemergesort ( workspace,0,1) called Recursivemergesort (workspace,0,0) again, at which point the status in the stack is as follows:


Program run here, finally there is a way to return the results of--recursivemergesort (workspace,0,0), the method of execution of the logic is the subscript in the array from 0 to 0 of the elements to merge, the segment has only one element, so do not merge, return immediately.

Once the method is return, it means that the method ends and Recursivemergesort (workspace,0,0) pops up from the stack. At this point, the program jumps to the second line in the code snippet (ii):

Recursivemergesort (workspace,1,1);

The method is in the stack, similar to Recursivemergesort (workspace,0,0), without merging, directly returning, the method out of the stack.

The degree jumps to the third line in the code snippet (ii):

Merge (workspace,0,0,1);

That is, the first two elements of an array are merged (naturally, the merge (workspace,0,0,1) is accompanied by a stack and a stack).

At this point, the code fragment (ii) is completed, the Recursivemergesort (workspace,0,1) method out of the stack, the program jumps to the second line of code fragment (c):

Recursivemergesort (workspace,2,3);

This method merges the third and fourth elements of an array, similar to the process of executing recursivemergesort (workspace,0,1), and eventually merges the third and fourth elements into a sort order.

Then, the program jumps to the third line of the code snippet (three):

Merge (workspace,0,1,3);

Merges the two subsequence (the first second element is a group, and the third fourth element is a group), which is already sorted in the preceding sequence.

Then Recursivemergesort (workspace,0,3) out of the stack, the program jumps to the second line of code snippet (iv):

Recursivemergesort (workspace,4,7);

The four elements of the right half of the array are sorted, followed by a series of stacks, stacks, and finally the last four elements are arranged. At this point, the left and right halves of the array are in order.

Then the program jumps to the code snippet (iv) on the third line:

Merge (workspace,0,3,7);

The left half of the array is merged with the right half part.

Then Recursivemergesort (workspace,4,7) out of the stack, MergeSort () out of the stack, the last main () method out of the stack, the program ends.


Algorithm analysis

First, analyze the number of copies.

If there are 8 elements in the array to be sorted, the merge sort needs to be divided into 3 layers, the first layer has four self-arrays containing two data items, the second layer contains two sub-arrays containing four data items, and the third layer contains a sub-array of 8 data items. When merging sub-arrays, all elements of each layer undergo a copy (copied from the original array to the workspace array), and the total number of copies is 3*8=24 times, that is, the number of layers multiplied by the total number of elements.

The total number of elements is n, the number of layers is log2n, and the total number of copies is n*log2n.

In fact, in addition to copying from the original array to the workspace array, you also need to copy from the workspace array to the original array, so the final replication count is 2*n*log2n.

In large O notation, constants can be ignored, so the time complexity of the merge sort is O (n log2n).

In general, the time consumption of the copy operation is much larger than the time consumption of the comparison operation, and the time complexity is dominated by the number of copies.

Let's look at the number of comparisons here.

In a merge sort, the number of comparisons is always less than the number of copies. Now given two sub-arrays with four elements, first look at the worst case and the best case comparison.


In the first case, the data item size is staggered, so 7 comparisons must be made, and in the second case an array is smaller than all the elements in the other array, so only 4 comparisons are required.

When merging two sub-arrays, if the total number of elements is n, the best case comparison is N/2, and the worst case comparison is N-1.

Assuming that the total number of elements in the array is n, the first layer needs to be N/2, the total number of elements per merge is 2, then the first layer needs N/4, the total number of elements per merge is 4; the first layer needs to be N/8, and the total number of elements for each merge is 8 ... The last merge number is 1, and the total number of merged elements is N. The total number of layers is log2n.

The best case comparison totals are:

N/2* (2/2) + n/4* (4/2) +n/8* (8/2) +...+1* (N/2) = (N/2) *log2n

The best case comparison totals are:

n/2* (2-1) + n/4* (4-1) +n/8* (8-1) +...+1* (N-1) =

(N-N/2) + (N-N/4) + (N-N/8) +...+ (N-1) =

n*log2n-(1+n/2+n/4+.) < n*log2n

Visible, the number of comparisons is between (N/2) *log2n and n*log2n. If the large O notation is used, the time complexity is also O (n log2n).

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Sorting algorithm (four)--merge sort and recursion

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.