算法导论--JAVA实现合并排序详解

时间:2022-06-25 12:32:56

最近复习算法的基本知识,主要是看《算法导论》,根据书本中的伪代码写java代码。以下是合并排序的代码:

public class MergeSort {
/**
* @Title: merge
* @Description:将左右两个已排序的子数组合并为一个已排序的数组
* @param A
* @param p
* @param q
* @param r
* @date 2016年3月3日
*/
public static void merge(int[] A, int p, int q, int r) {
// p为左数组的起点下标,q为左数组的终点下标,n1即为左数组的元素个数
int n1 = (q - p) + 1;
// q+1为右数组的起点下标,r为右数组的终点下标,n2即为右数组的元素个数
int n2 = (r - (q + 1)) + 1;
// 两个数组各加入一个哨兵标志值,用于标识无牌,所以数组长度+1
int[] leftArray = new int[n1 + 1];
int[] rightArray = new int[n2 + 1];
// 从原数组拷贝n1个元素到左数组
for (int i = 0; i < n1; i++) {
leftArray[i] = A[p + i];
}
// 从原数组拷贝n2个元素到右数组
for (int i = 0; i < n2; i++) {
// 右数组的起点坐标为q+1
rightArray[i] = A[(q + 1) + i];
}
// 插入哨兵标志,书中的伪代码为正无穷大,使任何数值与其相比均为较小。(该设计很巧妙,否则要每次判断子数组是否遍历结束)
// java中应该使用类似Double.POSITIVE_INFINITY的值,此处仅用integer的最大值
leftArray[n1] = Integer.MAX_VALUE;
rightArray[n2] = Integer.MAX_VALUE;
int i = 0, j = 0;
// 从两个牌堆中取出牌,比较后合并回A数组
// r为整个数组的最后一个元素的下标,而不是数组的length,循环a.length=r+1次
for (int k = p; k < r + 1; k++) {
// 比较左右数组的第i,第j个元素,把较小值填入原数组对应k位置,如某子数组取出较小值,则露出下一个值
if (leftArray[i] <= rightArray[j]) {
A[k] = leftArray[i];
i = i + 1;
} else {
A[k] = rightArray[j];
j = j + 1;
}
}

}

/**
* @Title: sort
* @Description:
* @param array
* @param p
* @param r
* @date 2016年3月3日
*/
public static void sort(int[] array, int p, int r) {
//如果p>=r,则数组中至多只有一个元素,即无需排序。
if (p < r) {
// 数组切分为两个,找出切分的下标
int q = (int) Math.floor((p + r) / 2);
sort(array, p, q);
sort(array, q + 1, r);
// 合并
merge(array, p, q, r);
}

}

public static void main(String[] args) {
int[] array = { 9, 5, 2, 4, 7, 1, 3, 2, 6 };
sort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}

}

算法导论中说明该算法的举例(纸牌游戏)很贴切,很方便理解,如下:

算法导论--JAVA实现合并排序详解

附原伪代码:

算法导论--JAVA实现合并排序详解