归并排序
归并排序是采用分治法的一个非常典型应用。
分治法:即先使每个子序列有序,再使整个子序列段间有序。
二路归并:即将两个有序表合并成一个有序表的过程,归并排序可以分为划分部分和合并部分。
多路归并:除了典型的二路归并还有多路归并。
归并排序的重要知识点:
- 时间复杂度: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代表每个归并段的数据
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举例: