归并排序
归并排序的思想就是分治法,分两步走,第一步,将需要排序的数组分解为子序列,对子序列进行排序;第二步就是对有序子序列进行排序,合并成一个有序的序列。
public static void sort(int[] arr) {
//临时数组
int[] tempArr = new int[arr.length];
sort(arr, tempArr, 0, arr.length - 1);
}
private static void sort(int[] arr,int[] tempArr, int startIndex,int endIndex) {
if(endIndex <= startIndex) {
return;
}
//中部下标
int middleIndex = startIndex + (endIndex - startIndex) / 2;
//不断拆分数组,采用二分法
sort(arr, tempArr, startIndex, middleIndex);
sort(arr, tempArr, middleIndex+1, endIndex);
//归并
merge(arr, tempArr, startIndex, middleIndex, endIndex);
}
private static void merge(int[] arr, int[] tempArr, int startIndex, int middleIndex, int endIndex) {
//复制需要合并的数据
for(int s = startIndex; s <= endIndex; s++) {
tempArr[s] = arr[s];
}
//左边首位下标
int left = startIndex;
//右边首位下标
int right = middleIndex + 1;
for(int k = startIndex; k <= endIndex; k++) {
//如果左边的首位下标大于中部下标,证明左边的数据已经排序好了。
if(left > middleIndex) {
arr[k] = tempArr[right++];
}
//如果右边的首位下标大于数组长度,证明右边的数据已经排序好了。
else if(right > endIndex) {
arr[k] = tempArr[left++];
}
//将右边的首位排入,然后右边的下标加1。
else if(tempArr[right] < tempArr[left]) {
arr[k] = tempArr[right++];
}
//将左边的首位排入,然后左边的下标加1.
else {
arr[k] = tempArr[left++];
}
}
}
我们可以发现 merge 方法中只有一个 for 循环,直接就可以得出每次合并的时间复杂度为 O(n) ,而分解数组每次对半切割,属于对数时间 O(log n) ,合起来等于 O(log2n) ,也就是说,总的时间复杂度为 O(nlogn) 。