【问题标题】:merge sort list java合并排序列表java
【发布时间】:2015-06-16 18:33:51
【问题描述】:

此代码的输出始终是输入的最后一位。 找不到原因。我递归使用归并排序,结果是错误的。我想可能是列表重叠了。

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;
    }
}

测试输入为 5、4、3、2、1。 但是输出是 1, 1, 1, 1, 1。 所以,这个合并方法肯定有问题

【问题讨论】:

  • 您是否使用调试器单步调试过您的代码?
  • 您应该使用调试器,并可能在每一步打印排序列表的内容以检查输出。

标签: java list mergesort


【解决方案1】:

快速解决问题的方法是更换:

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());

与:

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()));

您为分区创建新的ArrayLists,然后立即将引用更改为原始列表的视图。


列表的分区是正确完成的,但是,因为您使用的是视图而不是浅拷贝,所以在合并期间您正在更改您的分区。

通常,如果你正在做一个改变原始列表的排序,你不会从那个方法返回任何东西,所以像:

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++));
    }
  }
}

原始列表未发生突变的替代方法可能是:

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;
  }
}

【讨论】:

    【解决方案2】:

    subList 方法从原始列表创建一个新列表,但仍保留对原始元素的引用,因此在第一个中所做的任何更改都会影响第二个,反之亦然。 在您的合并方法中,您将覆盖原始列表,同时更改子列表中未通过您的 if 条件的较大元素。有关此事的更多信息请参考this post

    【讨论】:

    • 是的,你是对的!我只是意识到子列表仍然保留对原始列表的引用。谢谢你!
    猜你喜欢
    • 2014-12-02
    • 2012-01-18
    • 2020-10-25
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 2011-05-17
    • 2015-05-12
    相关资源
    最近更新 更多