简体   繁体   English

合并排序列表Java

[英]merge sort list java

The output of this code is always the last digit of the input. 此代码的输出始终是输入的最后一位。 Cannot find the reason.I use merge sort recursively, and the result is wrong. 找不到原因。我递归地使用合并排序,结果是错误的。 I thought maybe the list being overlapped. 我以为清单可能重叠了。

public class MergeSort {
    public static List<Integer> Sort(List<Integer> list) {
        if (list.size() <= 1) {
            return list;
        }
        List<Integer> aList = new ArrayList<Integer>();
        aList = list.subList(0, list.size() / 2);

        List<Integer> bList = new ArrayList<Integer>();
        bList = list.subList(list.size() / 2, list.size());

        Sort(aList);
        Sort(bList);

        merge(aList, bList, list);
        return list;
    }

    private static List<Integer> merge(List<Integer> alist,
        List<Integer> blist, List<Integer> list) {
        int alistIndex = 0, blistIndex = 0, listIndex = 0;
        while (alistIndex < alist.size() && blistIndex < blist.size()) {
            if (alist.get(alistIndex) < blist.get(blistIndex)) {
                list.set(listIndex, alist.get(alistIndex));
                alistIndex++;
            } else {
                list.set(listIndex, blist.get(blistIndex));
                blistIndex++;
            }
            listIndex++;
        }
        List<Integer> rest;
        if (alistIndex == alist.size()) {
            rest = blist.subList(blistIndex, blist.size());
            for(int c = blistIndex; c < rest.size(); c++){
                list.set(listIndex, blist.get(c));
                listIndex++;
            }
        } else {
            rest = alist.subList(alistIndex, alist.size());
            for(int c = alistIndex; c < rest.size(); c++){
                list.set(listIndex, alist.get(c));
                listIndex++;
            }
        }
        return list;
    }
}

The test input is 5, 4, 3, 2, 1. But the output is 1, 1, 1, 1, 1. So, there must have some wrong with this merge method 测试输入为5、4、3、2、1。但是输出为1、1、1、1、1。因此,此合并方法一定存在一些错误。

The subList method creates a new list from the original one, but still holds a reference to the original elements, such that any change made in the first will affect the second and vice-versa. subList方法从原始列表创建一个新列表,但仍保留对原始元素的引用,因此对第一个元素所做的任何更改都会影响第二个列表,反之亦然。 In your merge method, you are overwriting your original list and at the same time changing the greater elements in the sublist that do not pass your if condition. 在合并方法中,您将覆盖原始列表,同时更改子列表中不通过if条件的较大元素。 Please refer to for this post more information on the matter 有关此问题,请参阅这篇文章的更多信息。

The quick fix to your problem is replacing: 解决您的问题的快速方法是更换:

List<Integer> aList = new ArrayList<Integer>();
aList = list.subList(0, list.size() / 2);

List<Integer> bList = new ArrayList<Integer>();
bList = list.subList(list.size() / 2, list.size());

with: 有:

List<Integer> aList = new ArrayList<Integer>(list.subList(0, list.size() / 2));
List<Integer> bList = new ArrayList<Integer>(list.subList(list.size() / 2, list.size()));

You create new ArrayList s for your partitions then immediately change the reference to a view of your original list. 您为分区创建新的ArrayList ,然后立即将引用更改为原始列表的视图。


The partitioning of the list is being done correctly, however, because you are using the view instead of the shallow copies, during the merge you are changing your partitions. 列表的分区正确完成了,但是,由于您使用的是视图而不是浅表副本,因此在合并过程中,您正在更改分区。

Usually if you are doing a sort that mutates the original list, you don't return anything from that method, so something like: 通常,如果您要进行的操作使原始列表发生突变,则不会从该方法返回任何内容,因此类似:

public class MergeSort {
  public static void sort(List<Integer> list) {
    if (list.size() < 2) {
      return;
    }
    int mid = list.size()/2;
    List<Integer> left = new ArrayList<Integer>(list.subList(0, mid));
    List<Integer> right = new ArrayList<Integer>(mid, list.size()));

    sort(left);
    sort(right);
    merge(left, right, list);
  }

  private static void merge(
      List<Integer> left, List<Integer> right, List<Integer> list) {
    int leftIndex = 0;
    int rightIndex = 0;
    int listIndex = 0;

    while (leftIndex < left.size() && rightIndex < right.size()) {
      if (left.get(leftIndex) < right.get(rightIndex)) {
        list.set(listIndex++, left.get(leftIndex++));
      } else {
        list.set(listIndex++, right.get(rightIndex++));
      }
    }
    while (leftIndex < left.size()) {
      list.set(listIndex++, left.get(leftIndex++));
    }
    while (rightIndex < right.size()) {
      list.set(listIndex++, right.get(rightIndex++));
    }
  }
}

The alternative where the original list isn't mutated could be: 不更改原始列表的替代方法可能是:

public class MergeSort {
  public static List<Integer> sorted(List<Integer> list) {
    if (list.size() < 2) {
      return list;
    }
    int mid = list.size()/2;
    return merged(
        sorted(list.subList(0, mid)), 
        sorted(list.subList(mid, list.size())));
  }

  private static List<Integer> merged(List<Integer> left, List<Integer> right) {
    int leftIndex = 0;
    int rightIndex = 0;
    List<Integer> merged = new ArrayList<Integer>();

    while (leftIndex < left.size() && rightIndex < right.size()) {
      if (left.get(leftIndex) < right.get(rightIndex)) {
        merged.add(left.get(leftIndex++));
      } else {
        merged.add(right.get(rightIndex++));
      }
    }
    merged.addAll(left.subList(leftIndex, left.size()));
    merged.addAll(right.subList(rightIndex, right.size()));
    return merged;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM