java - 合并排序/合并方法的实现
问题描述
我试图实现归并排序算法。合并方法可能是错误的。到目前为止,这是我的代码:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
mergesort(list, 0, list.size() - 1);
}
private static <T extends Comparable<? super T>> void mergesort(List<T> list, int i, int j) {
if (j - i < 1)
return;
int mid = (i + j) / 2;
mergesort(list, i, mid);
mergesort(list, mid + 1, j);
merge(list, i, mid, j);
}
private static <T extends Comparable<? super T>> void merge(List<T> a, int p, int q, int r) {
int half = q - p + 1;
int otherhalf = r - q;
List<T> left = new ArrayList<T>();
List<T> right = new ArrayList<T>();
for (int i = 0; i < half; i++) {
left.add(i, a.get(p + i));
}
for (int i = 0; i < otherhalf; i++) {
right.add(i, a.get(q + i + 1));
}
int leftindex, rightindex, resultindex;
leftindex = rightindex = resultindex = 0;
while (leftindex < left.size() || rightindex < right.size()) {
if (leftindex < left.size() && rightindex < right.size()) {
if (left.get(leftindex).compareTo(right.get(rightindex)) < 0) {
a.set(resultindex, left.get(leftindex));
resultindex++;
leftindex++;
} else {
a.set(resultindex, right.get(rightindex));
resultindex++;
rightindex++;
}
} else if (leftindex < left.size()) {
a.set(resultindex, left.get(leftindex));
resultindex++;
leftindex++;
} else if (rightindex < right.size()) {
a.set(resultindex, right.get(rightindex));
resultindex++;
rightindex++;
}
}
}
我测试了它。作为输入,我选择[5, 6, 1, 4]
.
输出是[1, 1, 4, 4]
:
看来我在合并方法中没有到达位置 5 和 6。所以我想,我必须增加一些东西,但我不知道在哪里?有谁能够帮我 ?
解决方案
问题被resultindex
初始化为0
而不是p
.
以下是其他一些注意事项:
- 将第一个排除值的索引用于右限制而不是最后一个元素的索引会更简单。它避免
+ 1
了可能导致一个错误的调整。 - 比较应该
if (left.get(leftindex).compareTo(right.get(rightindex)) <= 0)
代替<
以确保稳定排序。 - 测试
else if (rightindex < right.size())
是多余的。 - 您可以通过编写 3 个循环来减少测试的数量:一个只要两半都有成员,然后一个复制左半部分的其余部分,最后一个复制右半部分的其余部分。
- 你的变量名在java中不是惯用的。
这是一个更正的版本:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
mergesort(list, 0, list.size());
}
private static <T extends Comparable<? super T>> void mergesort(List<T> list, int i, int j) {
if (j - i < 2)
return;
int mid = (i + j) / 2;
mergesort(list, i, mid);
mergesort(list, mid, j);
merge(list, i, mid, j);
}
private static <T extends Comparable<? super T>> void merge(List<T> a, int p, int q, int r) {
int leftLen = q - p;
int rightLen = r - q;
List<T> left = new ArrayList<T>();
List<T> right = new ArrayList<T>();
for (int i = 0; i < leftLen; i++) {
left.add(i, a.get(p + i));
}
for (int i = 0; i < rightLen; i++) {
right.add(i, a.get(q + i));
}
int leftIndex = 0;
int rightIndex = 0;
int resultIndex = p;
while (leftIndex < leftLen && rightIndex < rightLen) {
if (left.get(leftIndex).compareTo(right.get(rightIndex)) <= 0) {
a.set(resultIndex, left.get(leftIndex));
resultIndex++;
leftIndex++;
} else {
a.set(resultIndex, right.get(rightIndex));
resultIndex++;
rightIndex++;
}
}
while (leftIndex < leftLen) {
a.set(resultIndex, left.get(leftIndex));
resultIndex++;
leftIndex++;
}
while (rightIndex < rightLen) {
a.set(resultIndex, right.get(rightIndex));
resultIndex++;
rightIndex++;
}
}
此外,没有必要保存右半部分,因为它的元素在被复制之前永远不会被覆盖。实际上复制右半部分的其余部分是没有用的,因为这些元素已经到位。
这是一个简化版本:
private static <T extends Comparable<? super T>> void merge(List<T> a, int p, int q, int r) {
int half = q - p;
List<T> left = new ArrayList<T>();
for (int i = 0; i < half; i++) {
left.add(i, a.get(p + i));
}
int leftIndex = 0;
int rightIndex = q;
int resultIndex = p;
while (leftIndex < half && rightIndex < r) {
if (left.get(leftIndex).compareTo(a.get(rightIndex)) <= 0) {
a.set(resultIndex, left.get(leftIndex));
resultIndex++;
leftIndex++;
} else {
a.set(resultIndex, a.get(rightIndex));
resultIndex++;
rightIndex++;
}
}
while (leftIndex < half) {
a.set(resultIndex, left.get(leftIndex));
resultIndex++;
leftIndex++;
}
}
进一步简化代码:
- 数组
List
不需要动态,left
- 一些局部变量也可以省略
- 组合测试使最后一个循环无用。
这是简化但可能不太可读的代码:
private static <T extends Comparable<? super T>> void merge(List<T> a, int p, int q, int r) {
int i, half = q - p;
T[] left = new T[half];
for (i = 0; i < half; i++)
left[i] = a.get(p + i);
for (i = 0; i < half; ) {
if (q == r || left[i].compareTo(a.get(q)) <= 0)
a.set(p++, left[i++]);
else
a.set(p++, a.get(q++));
}
}
推荐阅读
- excel - Excel VLOOKUP + SUMPRODUCT 用于多个
- javascript - 如何让一个函数在不重复数字的情况下选择一个随机数,然后在遍历每个数字后重新开始?
- mongodb - 调用 mongoc_collection_find 函数时如何出错?
- javascript - MDN
如果最大长度换行? - amazon-web-services - 如何将 s3 中的所有视频文件连续流式传输到 vue 应用程序?
- java - 在响应正文中通过“findAll”搜索时出现异常“没有此类字段:类的年龄:java.util.HashMap$Node”
- laravel - Laravel如何从自己的表中设置会话并显示到视图
- google-sheets - 谷歌表格:在输入范围内映射 GOOGLEFINANCE 函数
- java - 如何在 Eclipse 中获取活动 c 项目的名称?
- javascript - 如何使用抽象来修复类的相关化?