Merge sort
Ten classic sorting algorithm!
Foreword
pleasebe sureLook at this: sorting algorithms pre-knowledge + code environment ready .
When the contents of the above are ready, then start merge sort it!
Merge sort
1945 by John von Neumann first proposed (John von Neumann).
Implementation process
- ① keep the average current sequence is divided into two sub-sequence
until it re-division (only one element in the sequence) - ② 2 subsequences will continually merge into an ordered sequence
until finally only an ordered sequence
Sequence into -divide
sort(0, array.length);
-----------------------------------------------------
/**
* 对 [begin, end) 范围的数据进行归并排序
*/
private void sort(int begin, int end){
if(end - begin < 2) return; // 至少要2个元素
int mid = (begin + end) >> 1;
sort(begin, mid); // 归并排序左半子序列
sort(mid, end); // 归并排序右半子序列
merge(begin, mid, end); // 合并整个序列
}
Sequences into -merge
Merged into a new sequence
The idea for the merger of two sequences: the sequence of elements in the left and right sequences one by one comparison, the smaller into a new sequence , the last new elements of a sequence in ascending inevitable.
The figure li, ri representing points to the left element and right sequence index , AI element is new sequence (SEQ combined) of the index ;
[li] representing a left sequence li position elements , [ri] indicates the R sequence ri position the element , as a new sequence {ai ai] position elements ;
- The first round: [li] <[ri], [li] into the new array, [ai]] = [li, li ++; ai ++;
- Second round: [li]> [ri], [ri] into the new array, [ai]] = [ri, ri ++; ai ++;
- Third round: [li] <[ri], [li] into the new array, [ai]] = [li, li ++; ai ++;
- Fourth round: left traversal sequence has been completed , the remaining elements of the sequence directly to the right into the new sequence, the new sequence obtained (in ascending order).
Situ consolidation -merge
When you merge two sequences, not necessarily to be merged into the new space, it is reasonable to use the original space to achieve in-situ consolidation .
E.g:
- The array of the left half of [the begin, MID) , the backup to leftArray;
- Then leftArray deemedLeft subsequence, Arrary the right half of [mid, end] consideredThe right sequence;
- The sequence left and right sequences incorporated into the array.
merge process:
- li <ri
Array [V] = leftArray [li];
li ++ and ++; - li> = to
array [ai] = array [a];
to ++, ai ++;
Sequence {3, 8, 6, 10} of merge sort:
Sequence {3, 6, 8, 10} for merge sort: left end sequences first traversal , then merging is ended.
Sequence {8, 10, 3, 6} of merge sort: Right before the end of the sequence , the rest will all fit on the left.
Situ consolidation -merge- achieve
/**
* 将 [begin, mid) 和 [mid, end) 范围的序列合并成一个有序序列
*/
private void merge(int begin, int mid, int end){
int li = 0, le = mid - begin; // 左边数组(基于leftArray)
int ri = mid, re = end; // 右边数组(array)
int ai = begin; // array的索引
// 备份左边数组到leftArray
for(int i = li; i < le; i++){
leftArray[i] = array[begin + i];
}
// 如果左边还没有结束
while(li < le){ // li == le 左边结束, 则直接结束归并
if(ri < re && cmp(array[ri], leftArray[li]) < 0){ // cmp改为<=0会失去稳定性
array[ai++] = array[ri++]; // 右边<左边, 拷贝右边数组到array
}else{
array[ai++] = leftArray[li++]; // 左边<=右边, 拷贝左边数组到array
}
}
}
Merge sort complete code
/**
* 归并排序
*/
@SuppressWarnings("unchecked")
public class MergeSort <T extends Comparable<T>> extends Sort<T> {
private T[] leftArray;
@Override
protected void sort() {
// 准备一段临时的数组空间, 在merge操作中使用
leftArray = (T[])new Comparable[array.length >> 1];
sort(0, array.length);
}
/**
* 对 [begin, end) 范围的数据进行归并排序
*/
private void sort(int begin, int end){
if(end - begin < 2) return; // 至少要2个元素
int mid = (begin + end) >> 1;
sort(begin, mid); // 归并排序左半子序列
sort(mid, end); // 归并排序右半子序列
merge(begin, mid, end); // 合并整个序列
}
/**
* 将 [begin, mid) 和 [mid, end) 范围的序列合并成一个有序序列
*/
private void merge(int begin, int mid, int end){
int li = 0, le = mid - begin; // 左边数组(基于leftArray)
int ri = mid, re = end; // 右边数组(array)
int ai = begin; // array的索引
// 备份左边数组到leftArray
for(int i = li; i < le; i++){
leftArray[i] = array[begin + i];
}
// 如果左边还没有结束
while(li < le){ // li == le 左边结束, 则直接结束归并
if(ri < re && cmp(array[ri], leftArray[li]) < 0){ // cmp改为<=0会失去稳定性
array[ai++] = array[ri++]; // 右边<左边, 拷贝右边数组到array
}else{
array[ai++] = leftArray[li++]; // 左边<=右边, 拷贝左边数组到array
}
}
}
}
20000 generates values are sorted in [1, 10000] random number:
Complexity and stability
Time spent in recursive merge sort :
- T (n) = 2 * T (n / 2) + O (n)
- T(1) = O(1)
- T (n) / n = T (n / 2) / (n / 2) + O (1)
The computational complexity of the recursion formula :
Order S n- = T (n-) / n-
- S(1) = O(1)
- S n = S (n / 2) + O (1) = S (n / 4) + O (2) = S (n / 8) + O (3) = S (n / 2 k ) + O (k ) = S (1) + O (logn) = O (logn)
- T n = n * S n = O (nlogn)
Because merge sort is always evenly divided sub-columns , so
- Preferably, the worst case time complexity are O (nlogn)
- Merge sort belongs to the stable sort
- Merge sort space complexity is O (n-/ logN + 2) = O (n-)
n-/ 2 for temporary storage of the left array, logn recursive call because
Common recursive and complexity
After the encounter complex complexity of computing time, write recursive direct look at this table can be.
LeetCode Zhenti
88. merge two ordered arrays
Topic Address: 88. merge two ordered arrays
topic:
Give you two ordered array of integers nums1 and nums2, you will nums2 merged into nums1 in the num1 become an ordered array.
Description:
- And initializing the number of elements nums1 nums2 of m and n.
- You can assume nums1 sufficient space (space equal to or greater than m + n) to save the elements of nums2.
Example:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
A thought: front to back merger
Were combined in situ, scratch back nums1 combined, nums2 element inserted nums1 need to move elements, less efficient .
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int li = 0, ri = 0, ai = 0, m2 = m; // 备份一下m
while(ri < n){ //nums2遍历完则直接结束
if(nums1[li] <= nums2[ri] && li < m2){
li++;
ai++;
}else{ // nums1[li] >= nums2[ri]
// 要令ri指向元素插入到ai, 首先将 ai到ai+li往后移1位
for(int i = m+n-1; i > ai; i--){
nums1[i] = nums1[i - 1];
}
nums1[ai++] = nums2[ri++];
li++;
m2++;
}
}
}
}
Thinking two: Merge from the back
In an idea on the basis of the front to back merge becomes combined from the back .
When combined in situ without moving element, nums1 combined from the back, the nums2 element into nums1, high efficiency .
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int len = m + n; //从后往前移, 需要合并后的总长度
for(int i = len - 1; i >=0; i--){
if(m>0 && n>0 && nums1[m-1] > nums2[n-1] || n==0){
nums1[i] = nums1[--m];
}else{
nums1[i] = nums2[--n];
}
}
}
}