归并排序

160 阅读2分钟

基本思想:采用分治策略,将问题分解成小问题,然后递归求解,然后再将各个部分的答案修补在一起。 如:

8 4 5 7 1 3 6 2 分解:

8 4 5 7 - 1 3 6 2

8 4 - 5 7 -- 1 3 - 6 2

8-4 -- 5-7 --- 1-3 -- 6-2

合并:

4 8 - 5 7 -- 1 3 - 2 6

4 5 7 8 - 1 2 3 6

1 2 3 4 5 6 7 8

共合并了7次,最后一次就是合并两个有序数组,左右分别两个指针,如果某个序列已经填完,酒直接把另一个序列剩余元素全部填入。

public static void mergeSort(int[] arr, int left, int right, int[] temp) 
{
	if (left < right) 
    {
    	int mid = (left + right)/2;//中间索引
        //向左递归进行分解
        mergeSort(arr, left, mid, temp);
        //向右递归进行分解
        mergeSort(arr, mid+1, right, temp);
        //合并
        merge(arr, left, mid, right, temp)
    }
}

//合并的方法:
/*
arr是原始数组,left是左边有序序列的初始索引,mid是中间索引,right是右边索引,temp是中转数组。
*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) 
{
	int i = left;
    int j = right;
    int t = 0;//指向temp数组的当前索引
    //先把左右两边有序数据按规则填充到temp数组中,直到左右两边序列中有一边处理完毕
    while (i <= mid && j<= right)
    {
    	if(arr[i] <= arr[j]) 
        {
        	temp[t] = arr[i];
            i += 1;
            t += 1;
        } else 
        {
        	temp[t] = arr[j];
            j += 1;
            t += 1;
        }
    }
    //把剩余数据的一边的数据依次全部填充到temp中
    while (i <= mid) //如果左边剩余,就全部填充到左边
    {
    	temp[t] = arr[i];
        t += 1;
        i += 1;
    }
    while (j <= right) 
    {
    	temp[t] = arr[j];
        t += 1;
        j += 1;
    }
    //将temp数组的元素拷贝到arr中,但并不是每次都拷贝所有
    t = 0;
    int templeft = left;
    while (templeft <= right) 
    {
    	arr[templeft] = temp[t];
        t += 1;
        templeft += 1;
    }
}