归并排序
归并算法采用的是一种分治思想,将数组细分为许多子序列,先将所有的子序列排好序后进行合并,再对合并后的子序列进行排序,直到合并为原数组大小并排好顺序。若每次将一个序列二分,则成为2-路归并。
动图演示
测试代码:
public static void main(String[] args) {
int[] arr = {54, 23, 5, 2, 12, 11, 13, 21, 1, 32};
sort(arr, 0, arr.length - 1);
print(arr);
}
public static void sort(int[] arr, int left, int right) {
if (left == right) return;
int mid = left + (right - left) / 2;
//左侧
sort(arr, left, mid);
//右侧
sort(arr, mid + 1, right);
merge(arr, left, mid + 1, right);
}
//leftPtr左指针,rightPtr右指针,rightBound右边界
static void merge(int[] arr, int leftPtr, int rightPtr, int rightBound) {
int mid = rightPtr - 1;
//临时数组存储子序列
int[] temp = new int[rightBound - leftPtr + 1];
int i = leftPtr;
int j = rightPtr;
int k = 0;
//连续添加
while (i <= mid && j <= rightBound) {
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
//若单侧元素已经全部按顺序放入临时数组,将另一侧剩余元素直接添加到临时数组
while (i <= mid) temp[k++] = arr[i++];
while (j <= rightBound) temp[k++] = arr[j++];
//将排好序的临时数组,返回给原数组
for (int m = 0; m < temp.length; m++) {
arr[leftPtr + m] = temp[m];
}
}
static void swap(int[] arr, int i, int j) {
int tmep = arr[i];
arr[i] = arr[j];
arr[j] = tmep;
}
static void print(int[] arr) {
for (int i = 0; i < arr.length; i++)
System.out.println(arr[i] + " ");
}
运行结果:
复杂度与稳定性
时间复杂度为O(n*logn)。归并排序的形式可以看成为一个二叉树,需要遍历的次数就是二叉树的深度。
空间复杂度为O(n)。排序过程中使用了临时数组。
归并排序是稳定的。