Merge sort is an effective Sorting Algorithm Based on the Merge operation. This algorithm is a very typical application of Divide and Conquer.
Merge operations
Basic Ideas
The merge operation (merge) refers to the operation that combines two sorted sequences into one. The merge Sorting Algorithm depends on the merge operation.
The merge operation process is as follows:
Apply for a space, so that the size is the sum of two sorted sequences. This space is used to store the merged sequence.
Set two pointers. The initial position is the start position of the two sorted sequences respectively.
Compare the elements pointed to by the two pointers, select a relatively small element into the merging space, and move the pointer to the next position.
Repeat Step 3 until a pointer reaches the end of the sequence
Copy all the remaining elements of another sequence directly to the end of the merged sequence.
Merge operation Algorithm Implementation (c/c ++)
[Cpp]
Void Merge (SeqList R, int low, int m, int high)
{// Combine two ordered sub-files R [low.. m) and R [m + 1 .. high] into an ordered sub-file R [low .. high]
Int I = low, j = m + 1, p = 0; // set the Initial Value
RecType * R1; // R1 is a local vector. If p is defined as a pointer of this type, the speed is faster.
R1 = (ReeType *) malloc (high-low + 1) * sizeof (RecType ));
If (! R1) // failed to apply for Space
Error ("Insufficient memory available! ");
While (I <= m & j <= high) // when the two sub-files are not empty, the small ones are output to R1 [p ].
R1 [p ++] = (R [I]. key <= R [j]. key )? R [I ++]: R [j ++];
While (I <= m) // If the 1st sub-files are not empty, copy the remaining records to R1
R1 [p ++] = R [I ++];
While (j <= high) // If the 2nd sub-files are not empty, copy the remaining records to R1
R1 [p ++] = R [j ++];
For (p = 0, I = low; I <= high; p ++, I ++)
R [I] = R1 [p]; // after merging, copy the result back to R [low... high]
} // Merge
Void Merge (SeqList R, int low, int m, int high)
{// Combine two ordered sub-files R [low.. m) and R [m + 1 .. high] into an ordered sub-file R [low .. high]
Int I = low, j = m + 1, p = 0; // set the Initial Value
RecType * R1; // R1 is a local vector. If p is defined as a pointer of this type, the speed is faster.
R1 = (ReeType *) malloc (high-low + 1) * sizeof (RecType ));
If (! R1) // failed to apply for Space
Error ("Insufficient memory available! ");
While (I <= m & j <= high) // when the two sub-files are not empty, the small ones are output to R1 [p ].
R1 [p ++] = (R [I]. key <= R [j]. key )? R [I ++]: R [j ++];
While (I <= m) // If the 1st sub-files are not empty, copy the remaining records to R1
R1 [p ++] = R [I ++];
While (j <= high) // If the 2nd sub-files are not empty, copy the remaining records to R1
R1 [p ++] = R [j ++];
For (p = 0, I = low; I <= high; p ++, I ++)
R [I] = R1 [p]; // after merging, copy the result back to R [low... high]
} // Merge
Binary Merge Sorting
Merge Sorting is a Sort Algorithm Based on merge operations. It can be used for intra-order or out-of-order sorting.
Two-way Merge Sorting
Basic Ideas
Set two ordered sub-files (equivalent to the input heap) to the adjacent positions in the same vector: R [low .. m], R [m + 1 .. high], first merge them into a local temporary storage vector R1 (equivalent to the output heap), and then copy R1 back to R [low .. high.
(1) merging process
During the merge process, set the I, j, and p pointers, and their initial values point to the starting positions of the three record areas respectively. When merging, compare the keywords of R [I] and R [j] in sequence, and copy the records with smaller keywords to R1 [p, then add the pointer I or j of the copied record to 1 and the pointer p pointing to the copy position to 1.
Repeat this process until one of the two input sub-files has been completely copied (it may be called null ), copy the remaining records of another non-empty sub-file to R1.
(2) dynamically apply for R1
During implementation, R1 dynamically applies because the application space may be large, so it must be added to the application space for successful processing.
Algorithm Implementation
Bottom-up method
(1) Basic Idea of bottom-up
The basic idea of bottom-up sorting is to sort the files to be sorted by merging 1st rows [1 .. n] is considered as n ordered sub-files with a length of 1. These Sub-files are merged into two pairs. If n is an even number, an ordered sub-file with a length of 2 is obtained; if n is an odd number, the wheel of the last sub-file is empty (not involved in merging ). Therefore, after this merge, the length of the first ordered sub-file is 2, but the length of the last sub-file is still 1; 2nd merge is to merge the 1st merged sub-files in an orderly manner, so repeatedly until a sequential file with a length of n is obtained.
The preceding merge operation combines two ordered sub-files into an ordered sub-file, which is called "two-way Merge Sorting ". Similarly, there are k (k> 2) Merge Sorting.
(2) Two-way Merge Sorting Algorithm demonstration
[See animation demonstration]
(3) Merge Algorithms
Analysis:
In a merge, if the length of each sub-file is set to length (the length of the last sub-file may be smaller than length), the pre-merge R [1 .. n] contains a total of ordered sub-files:
R [1 .. length], [length + 1 .. 2 length],…, .
Note:
When the merge operation is called to merge adjacent sub-files, the number of sub-files may be odd, and the length of the last sub-file may be smaller than the length:
① If the number of sub-files is odd, the last sub-file does not need to be merged with other sub-files (that is, this round is empty );
② If the number of subfiles is an even number, note that the upper limit of the last subfile In the last pair is n.
Specific implementation algorithms:
[Cpp]
Void MergePass (SeqList R, int length)
{// Sort R [1 .. n] by merging
Int I;
For (I = 1; I + 2 * length-1 <= n; I = I + 2 * length)
Merge (R, I, I + length-1, I + 2 * length-1 );
// Merge two adjacent sub-files with length
If (I + length-1 <n) // There are two sub-files, the last of which is smaller than the length
Merge (R, I, I + length-1, n); // Merge the last two subfiles
// Note: If I ≤ n and I + length-1 ≥ n, the rotation of the remaining sub-file is empty and does not need to be merged.
} // MergePass
Void MergePass (SeqList R, int length)
{// Sort R [1 .. n] by merging
Int I;
For (I = 1; I + 2 * length-1 <= n; I = I + 2 * length)
Merge (R, I, I + length-1, I + 2 * length-1 );
// Merge two adjacent sub-files with length
If (I + length-1 <n) // There are two sub-files, the last of which is smaller than the length
Merge (R, I, I + length-1, n); // Merge the last two subfiles
// Note: If I ≤ n and I + length-1 ≥ n, the rotation of the remaining sub-file is empty and does not need to be merged.
} // MergePass
(4) two-way Merge Sorting Algorithm
[Cpp] view plaincopyprint? Void MergeSort (SeqList R)
{// Uses the bottom-up method to sort the R [1. n] by two-way Merging
Int length;
For (1 ength = 1; length <n; length * = 2) // merge
MergePass (R, length); // terminate when the length of an ordered segment is greater than or equal to n.
}
Void MergeSort (SeqList R)
{// Uses the bottom-up method to sort the R [1. n] by two-way Merging
Int length;
For (1 ength = 1; length <n; length * = 2) // merge
MergePass (R, length); // terminate when the length of an ordered segment is greater than or equal to n.
}
Note:
Although the bottom-up Merge Sorting Algorithm is more efficient, it is less readable.
Top-down method
Use the division and Control Method for top-down algorithm design, the form is more concise.
(1) three steps of the divide and conquer Law
Set the current range of Merge Sorting to R [low .. high]. The three steps of division and control are as follows:
① Decomposition: splits the current interval into two parts, that is, finding the split point
② Solution: recursively sort the R [low... mid] and R [mid + 1 .. high] in two subintervals;
③ Combination: Combine the sorted two subintervals R [low .. mid] and R [mid + 1 .. high] is merged into an ordered interval R [low .. high].
Recursive termination condition: the subinterval length is 1 (a record is naturally ordered ).
(2) specific algorithms
[Cpp]
Void MergeSortDC (SeqList R, int low, int high)
{// Sort the R [low .. high] by merging and dividing
Int mid;
If (low Mid = (low + high)/2; // Decomposition
MergeSortDC (R, low, mid); // recursively sorts R [low... mid]
MergeSortDC (R, mid + 1, high); // recursively sorts R [mid + 1 .. high]
Merge (R, low, mid, high); // combine two ordered zones into one ordered Zone
}
} // MergeSortDC
Void MergeSortDC (SeqList R, int low, int high)
{// Sort the R [low .. high] by merging and dividing
Int mid;
If (low Mid = (low + high)/2; // Decomposition
MergeSortDC (R, low, mid); // recursively sorts R [low... mid]
MergeSortDC (R, mid + 1, high); // recursively sorts R [mid + 1 .. high]
Merge (R, low, mid, high); // combine two ordered zones into one ordered Zone
}
} // MergeSortDC
(3) Execution Process of the algorithm MergeSortDC
The execution process of the algorithm MergeSortDC is shown in the recursive tree.
Example of Merge Sorting: the execution process of top-down two-way merge
3. Overall algorithm process demonstration
An example of merging and sorting: sort the linked list of a random vertex:
4. algorithm performance analysis
1. Stability
Merge Sorting is a stable sorting.
2. Storage Structure requirements
Available sequential storage structure. It is also easy to implement on the linked list.
3. Time Complexity
For files with a length of n, You need to merge them one by one. The time for each merge is O (n ), therefore, the time complexity is O (nlgn) in both the best and worst cases ).
4. spatial complexity
An auxiliary vector is required to store the results of merging two ordered sub-files. Therefore, the complexity of the auxiliary space is O (n). Obviously, it is not local sorting.