标签:编程技巧 原因 占用 简单 ali quic 原地排序 pre ble
/**
* 归并排序
* @param arr 排序数据
* @param n 数组大小
*/
public static void merge_sort(int[] arr, int n) {
merge_sort_c(arr, 0, n - 1);
}
// 递归调用函数
public static void merge_sort_c(int[] arr, int p, int r) {
// 递归终止条件
if (p >= r) {
return;
}
// 取p到r之间的中间位置q
int q = (p + r) / 2;
// 分治递归
merge_sort_c(arr, p, q);
merge_sort_c(arr, q + 1, r);
// 将 arr[p...q] 和 arr[q+1...r] 合并为 arr[p...r]
merge(arr[p...r],arr[p...q],arr[q + 1...r]);
}
/**
* merge 合并函数
* @param arr 数组
* @param p 数组头
* @param q 数组中间位置
* @param r 数组尾
*/
public static void merge(int[] arr, int p, int q, int r) {
if (r <= p) return;
// 初始化变量i j k
int i = p;
int j = q + 1;
int k = 0;
// 申请一个大小跟A[p...r]一样的临时数组
int[] tmp = new int[r - p + 1];
// 比较排序移动到临时数组
while ((i <= q) && (j <= r)) {
if (arr[i] <= arr[j]) {
tmp[k++] = arr[i++];
} else {
tmp[k++] = arr[j++];
}
}
// 判断哪个子数组中有剩余的数据
int start = i, end = q;
if (j <= r) {
start = j;
end = r;
}
// 将剩余的数据拷贝到临时数组tmp
while (start <= end) {
tmp[k++] = arr[start++];
}
// 将tmp中的数组拷贝回 arr[p...r]
for (int a = 0; a <= r - p; a++) {
arr[p + a] = tmp[a];
}
}
/**
* 快速排序
* @param arr 排序数组
* @param p 数组头
* @param r 数组尾
*/
public static void quickSort(int[] arr, int p, int r) {
if (p >= r)
return;
// 获取分区点 并移动数据
int q = partition(arr, p, r);
quickSort(arr, p, q - 1);
quickSort(arr, q + 1, r);
}
partition() 分区函数:
partition() 的实现有两种方式:
一种是不考虑空间消耗,此时非常简单。
/**
* 分区函数方式一
*
* @param arr 数组
* @param p 上标
* @param r 下标
* @return 函数返回 pivot 的下标
*/
public static int partition1(int[] arr, int p, int r) {
int[] xArr = new int[r - p + 1];
int x = 0;
int[] yArr = new int[r - p + 1];
int y = 0;
int pivot = arr[r];
// 将小于 pivot 的元素都拷贝到临时数组 X,将大于 pivot 的元素都拷贝到临时数组 Y
for (int i = p; i < r; i++) {
// 小于 pivot 的存入 xArr 数组
if (arr[i] < pivot) {
xArr[x++] = arr[i];
}
// 大于 pivot 的存入 yArr 数组
if (arr[i] > pivot) {
yArr[y++] = arr[i];
}
}
int q = x + p;
// 再将数组 X 和数组 Y 中数据顺序拷贝到 arr[p…r]
for (int i = 0; i < x; i++) {
arr[p + i] = xArr[i];
}
arr[q] = pivot;
for (int i = 0; i < y; i++) {
arr[q + 1 + i] = yArr[i];
}
return q;
}
另外一种有点类似选择排序。
/**
* 分区函数方式二
* @param arr 数组
* @param p 上标
* @param r 下标
* @return 函数返回pivot的下标
*/
public static int partition2(int[] arr, int p, int r) {
int pivot = arr[r];
int i = p;
for (int j = p; j < r; j++) {
if (arr[j] < pivot) {
if (i == j) {
++i;
} else {
int tmp = arr[i];
arr[i++] = arr[j];
arr[j] = tmp;
}
}
}
int tmp = arr[i];
arr[i] = arr[r];
arr[r] = tmp;
return i;
}
归并排序 | 快速排序 | |
---|---|---|
排序思想 | 处理过程由下到上,先处理子问题,然后在合并 | 由上到下,先分区,在处理子问题 |
稳定性 | 是 | 否 |
空间复杂度 | Q(n) | Q(1) 原地排序算法 |
时间复杂度 | 都为 O(nlogn) | 平均为 O(nlogn),最差为 O(n2) |
标签:编程技巧 原因 占用 简单 ali quic 原地排序 pre ble
原文地址:https://www.cnblogs.com/xiexiandong/p/13046825.html