归并排序
思路:
归并排序属于外部排序,因为在合并时,需要一个额外的数组。将待排序数据分成两部分,继续将两个子部分进行递归的归并排序;然后将已经有序的两个子部分进行合并,最终完成排序。
复杂度分析:
平均时间复杂度为O(nlogn),递归调用间接使用了辅助数组,需要额外的O(n)空间进行临时存储。故空间复杂度为O(n)
这里面要注意,求两个数的中点时,注意溢出问题
int mid =(head + rear) / 2;
这种方法不安全,当数很大的时候,(head + rear)可能会大于int最大值,导致溢出,所以可以考虑下面这种方式:
int mid =head + (head + rear)/ 2;
public class MergeSort {
/**
* 归并排序算法
* @param list 待排序的列表
* @param tempList 临时列表
* @param head 列表开始位置
* @param rear 列表结束位置
*/
public static void mergeSort(int[] list, int[] tempList, int head, int rear) {
if (head < rear) {
// 取中间值
int middle =head + (head + rear)/ 2;
// 递归划分列表的左序列
mergeSort(list, tempList, head, middle);
// 递归划分列表的右序列
mergeSort(list, tempList, middle + 1, rear);
// 合并列表
merge(list, tempList, head, middle + 1, rear);
}
}
/**
* 合并操作(列表的两两合并)
*/
public static void merge(int[] list, int[] tempList, int head, int middle, int rear) {
// 左指针尾
int headEnd = middle - 1;
// 右指针头
int rearStart = middle;
// 临时列表的下标
int tempIndex = head;
// 列表合并后的长度
int tempLength = rear - head + 1;
// 先循环两个区间段都没有结束的情况
while ((headEnd >= head) && (rearStart <= rear)) {
// 如果发现右序列大,则将此数放入临时列表
if (list[head] < list[rearStart]) {
tempList[tempIndex++] = list[head++];
} else {
tempList[tempIndex++] = list[rearStart++];
}
}
// 判断左序列是否结束
while (head <= headEnd) {
tempList[tempIndex++] = list[head++];
}
// 判断右序列是否结束
while (rearStart <= rear) {
tempList[tempIndex++] = list[rearStart++];
}
// 交换数据
for (int i = 0; i < tempLength; i++) {
list[rear] = tempList[rear];
rear--;
}
}
}
网友评论