归并排序
这是一种分治法的应用,就是对于一个待排序的序列,将它一分为二,二分为四……,分到最后,每一个序列中只会包含一个元素,这时,每一个小序列就已经有序了(因为只有一个元素,所以肯定是有序的)。然后将其两两归并排序,……四合为二,二合为一。这样就能完排序功能。
该排序算法有两个方法:
1.合并方法merge(),合并一个在某一位置分开,两边子序列分别有序的序列。
2.归并排序方法mergeSort(),这个方法递归调用,完成序列的拆分排序。
/**
* @Description 合并排序一个在startIndex到minIndex位置有序,且在midIndex到endIndex上有序的序列
* @param srcArray
* 源数组,且该数组在startIndex到midIndex位置上有序,在midIndex到endIndex上有序
* @param targetArray
* 目标数组,排序完成之后的数组,起始位置为srcArray的起始位置
* @param startIndex
* 排序开始位置 (不一定在srcArray的开始位置)
* @param midIndex
* 排序中间位置
* @param endIndex
* 排序结束位置
* @return
*/
public static void merge(int[] srcArray, int[] targetArray, int startIndex,
int midIndex, int endIndex) {
// 注意目标数组的起始位置k是startIndex,而非0,因为srcArray的起始位置要和targetArray中的起始位置相同
int i = startIndex, j = midIndex + 1, k = startIndex;
// 这里i,j用来指示由srcArray拆分出的两个有序子序列的起始位置
// 当某一个数组中的数字已经用完,那么就不用再循环比较了,直接将另一个数组中剩下的数字拼接到新数组中即可
while (i < midIndex + 1 && j < endIndex + 1) {
if (srcArray[i] < srcArray[j]) {
targetArray[k++] = srcArray[i++];
} else {
targetArray[k++] = srcArray[j++];
}
}
// 如果startIndex到midIndex数组中还剩下有数,那么将其拼接到目标数组targetArray中
while (i < midIndex + 1) {
targetArray[k++] = srcArray[i++];
}
// 如果midIndex到endIndex数组中还剩下有数,那么将其拼接到目标数组targetArray中
while (j < endIndex + 1) {
targetArray[k++] = srcArray[j++];
}
}
/**
* @Description 归并排序(递归),这个方法为什么需要一个开始位置和结束位置?因为这个数组在递归排序过程中逻辑上会拆分成很多小序列,
* (一分为二,二分为四……) 直到一个序列只包含一个数为止,
* 而这个startIndex和endIndex则是指示这些逻辑上的小数组在源数组中的正确位置。
* @param srcArray
* 待排序数组
* @param targetArray
* 目标数组
* @param startIndex
* 开始位置
* @param endIndex
* 结束位置
* @return
*/
public static void mergeSort(int[] srcArray, int[] targetArray,
int startIndex, int endIndex) {
int midIndex;
int[] tempArray = new int[1024]; // 该数组为临时数组,大小需要按照需要进行更改,必须>=源数组
// 特别注意:这是递归的出口,也就是指当序列一分为二,二分为四……,当序列被折分到子序列中只剩下一个元素的时候,
// 那么这个子序列就算是有序序列了(因为有一个元素,所以肯定算是有序列的)。
// 将其直接存放于target目标数组中即可
if (startIndex == endIndex) {
targetArray[startIndex] = srcArray[startIndex];
} else {
midIndex = (startIndex + endIndex) / 2;
mergeSort(srcArray, tempArray, startIndex, midIndex); // 递归排序左边的序列
mergeSort(srcArray, tempArray, midIndex + 1, endIndex); // 递归排序右边的序列
merge(tempArray, targetArray, startIndex, midIndex, endIndex); // 递归将排序好的序列(存放于temp中)进行2路归并
}
}