注:这里给出的代码方案都是通过递归完成的
---
归并排序(Merge Sort):
分而治之,递归实现
如果需要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分进行分别排序,再将排好序的数组合并在一起,这样整个数组就有序了
归并排序是稳定的排序算法,时间复杂度为O(nlogn),空间复杂度是O(n)
图解:
代码:
/**
* 归并排序
*
* @param arr 待排数组
* @param low 归并起始位置
* @param high 归并截至位置
*/
public static void mergeSort(int[] arr, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
// 分开
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
// 合并
mergeArray(arr, low, mid, high);
}
}
private static void mergeArray(int[] arr, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
// 数组被分成两部分,进行合并
// 两个数组中的元素进行比较,小的进入temp中
int i = low;
int k = 0;
int j = mid + 1;
while (i <= mid && j <= high) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= high) {
temp[k++] = arr[j++];
}
// 将temp数组中的数据,重新灌入被排序数组,此时数组顺序已经排好
for (int l = 0; l < temp.length; l++) {
arr[low + l] = temp[l];
}
}
注:
空间复杂度又称渐进空间复杂度,指的是随数据量的增加,额外需要使用的空间开销。前一次归并后的数组空间,可以被接下来的操作使用。所以该排序的空间复杂度是O(n)
---
快速排序(QuockSort):
如果需要排序数组中下标从p到r之间的一组数据,我们会选择从p到r之间的任意一个数据作为区分点,我们遍历p到r之间的数据,将小于区分点的数据放左边,大于区分点的数据放右边,然后将区分点放到中间
快速排序是一种原地排序,不稳定的排序,时间复杂度为O(nlogn),空间复杂度是O(n)
图解:
代码:
/**
* 快速排序
*
* @param arr 待排数组
* @param low 排序起始位置
* @param high 排序终止位置
*/
public static void quockSort(int[] arr, int low, int high) {
if (low > high) {
return;
}
int i = low;
int j = high;
int pivot = arr[low];
while (i < j) {
// 如果选取两端的数作为pivot,那么循环要从基数的对面开始,选取中间的基数则不需要考虑这个问题
while (i < j && arr[j] > pivot) {
j--;
}
while (i < j && arr[i] <= pivot) {
i++;
}
if (i < j) {
int c = arr[i];
arr[i] = arr[j];
arr[j] = c;
}
}
int p = arr[i];
arr[i] = arr[low];
arr[low] = p;
quockSort(arr, low, i - 1);
quockSort(arr, i + 1, high);
}
---
测试方法及生成随机数组方法:
/**
* 生成一个长度5-10的随机数组
*
* @return 随机数组
*/
private static int[] initArray() {
int len = 5 + new Random().nextInt(6);
int[] arr = new int[len];
for (int i = 0; i < arr.length; i++) {
arr[i] = new Random().nextInt(100);
}
return arr;
}
public static void main(String[] args) {
int[] arr2 = initArray();
System.out.println("排序之前的数组是:" + Arrays.toString(arr2));
quockSort(arr2,0,arr2.length-1);
System.out.println("排序之后的数组是:" + Arrays.toString(arr2));
}
---
关于 如果选取两端的数作为pivot,那么循环要从基数的对面开始 的参考博客:
https://blog.csdn.net/w282529350/article/details/50982650
---
测试结果,亲测有效:
归并:
排序之前的数组是:[71, 79, 11, 20, 68, 78, 95]
排序之后的数组是:[11, 20, 68, 71, 78, 79, 95]
快速:
排序之前的数组是:[44, 25, 17, 44, 71, 25, 66, 96, 36]
排序之后的数组是:[17, 25, 25, 36, 44, 44, 66, 71, 96]