Good Times [] data structure merge sort Zhenti + LeetCode

Ten classic sorting algorithm!
Here Insert Picture Description

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

Here Insert Picture Description

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).

Here Insert Picture Description

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.

Here Insert Picture Description

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:
Here Insert Picture Description

Sequence {3, 6, 8, 10} for merge sort: left end sequences first traversal , then merging is ended.
Here Insert Picture Description
Sequence {8, 10, 3, 6} of merge sort: Right before the end of the sequence , the rest will all fit on the left.
Here Insert Picture Description

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:
Here Insert Picture Description

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.
Here Insert Picture Description

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++;
    		}
    	}
    }
    
}

Here Insert Picture Description

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];
			 }
		 }		 
	 }
	 
 }

Here Insert Picture Description

Published 170 original articles · won praise 47 · views 20000 +

Guess you like

Origin blog.csdn.net/weixin_43734095/article/details/105127138