Java笔记:归并排序

归并排序

归并排序是采用分治法的一个非常典型应用。
分治法:即先使每个子序列有序,再使整个子序列段间有序。
二路归并:即将两个有序表合并成一个有序表的过程,归并排序可以分为划分部分和合并部分。
多路归并:除了典型的二路归并还有多路归并。

归并排序的重要知识点:

  • 时间复杂度:n*log2n
  • 空间复杂度:O(n)
  • 稳定性:稳定的

下面是二路归并排序的流程图:
二路归并

1 归并排序(递归)
public static void mergeSort(int[] array) {
    mergeSortInterna(array,0,array.length-1);
}
public static void mergeSortInterna(int[] array,
			int low,int high) {
    //low==high时,数组分解为单个元素,已经有序了。
   if(low >= high) {
        return;
    }
    int mid = (low+high)/2;
    mergeSortInterna(array,low,mid);
    mergeSortInterna(array,mid+1,high);
    //合并
    merge(array,low,mid,high);
}

合并举例
合并

public static void merge(int[] array,int low,int mid,int high) {

    int s1 = low;
    int s2 = mid+1;

    int[] tmpArr = new int[high-low+1];
    int i = 0;//tmpArr的数组下标
    //当两个归并段都有数据的时候
    while (s1 <= mid && s2 <= high) {
        //如果是小于,那么就不稳定了,取等于时应将第一个数组
        //的s1先计入数组tmpArr,而非是先把第二个数组的s2放入数组,
        //否则将会变得不稳定。
        if(array[s1] <= array[s2]) {
            tmpArr[i++] = array[s1++];
        }else {
            tmpArr[i++] = array[s2++];
        }
    }
    //2:
    while (s1 <= mid) {
        tmpArr[i++] = array[s1++];
    }
    while (s2 <= high) {
        tmpArr[i++] = array[s2++];
    }
    //tmpArr里面存放的是有序的数据
    //将tmpArr里面存放的有序的数据,放回到array里面
    for (int j = 0; j < tmpArr.length; j++) {
        array[low+j] = tmpArr[j];
    }
}
2 归并排序(非递归)
public static void mergeSort(int[] array) {
    //i代表归并段的数量
    for (int i = 1; i < array.length; i *= 2) {
        merge(array,i);
    }
}

gap划分及排序
gap划分

//gap代表每个归并段的数据
public static void merge(int[] array,int gap) {
    int[] tmpArr = new int[array.length];
    int k = 0;//下标

    int s1 = 0;
    int e1 = s1+gap-1;
    int s2 = e1+1;
    int e2 = s2+gap-1 < array.length 
                      ? s2+gap-1:array.length-1;
    //两个归并段都有数据
    while (s2 < array.length) {
        while (s1 <= e1 && s2 <= e2) {
            if(array[s1] <= array[s2]) {
                tmpArr[k++] = array[s1++];
            }else {
                tmpArr[k++] = array[s2++];
            }
        }
        while (s1 <= e1) {
            tmpArr[k++] = array[s1++];
        }
        while (s2 <= e2) {
            tmpArr[k++] = array[s2++];
        }
        s1 = e2+1;
        e1 = s1+gap-1;
        s2 = e1+1;
        e2 = s2+gap-1 < array.length ? s2+gap-1:array.length-1;
    }
    //判断是不是还有一个归并段,且这个归并段一定是s1那个段,
    //直接小于e1可能会越界
    while (s1 <= array.length-1) {
        tmpArr[k++] = array[s1++];
    }
    for (int i = 0; i < tmpArr.length; i++) {
        array[i] = tmpArr[i];
    }
}

对于索引s1, e1, s2, e2用gap==2举例
gap=2

发布了54 篇原创文章 · 获赞 6 · 访问量 4811

猜你喜欢

转载自blog.csdn.net/glpghz/article/details/104374968