【问题标题】:How can I implement mergesort for a ArrayList?如何为 ArrayList 实现归并排序?
【发布时间】:2021-04-16 01:45:48
【问题描述】:

我有一个用于ArrayList 的合并排序java 代码,但它不能正确排序ArrayList。但我没有发现错误。

代码是:

public void mergeSort(ArrayList<Integer> list, int beg, int fin) {
    if (beg < fin) {
        int mid= (beg + fin) / 2;
        mergeSort(list, beg, mid);
        mergeSort(list, mid + 1, fin);
        Merge(list, beg, mid, fin);
    }
}


public void Merge(ArrayList<Integer> list, int beg, int mid, int fin) {
    ArrayList<Integer> left = new ArrayList<>(list.subList(beg, mid));
    ArrayList<Integer> right = new ArrayList<>(list.subList(mid, fin));
    
    int i = 0;
    int j = 0;
    int k = beg;
    
    while (i < left.size() && j < right.size()) {
        if (left.get(i) <= right.get(i)) {
            list.set(k, left.get(i));
            i++;
        } else {
            list.set(k, right.get(j));
            j++;
        }
        k++;
    }
    
    while (i < left.size()) {
        list.set(k, left.get(i));
        i++;
        k++;
    }

    while (j < right.size()) {
        try {
            list.set(k, right.get(j));
            j++;
            k++;
        }
    }
}

当我从其他班级调用它时......

jpanel4.mergeSort(jpanel4.lista, 0, jpanel4.lista.size() - 1);

(合并在 jpanel4 类中)。

我将数组的合并排序代码转换为该代码,因为它可以与我拥有的其他代码一起正常工作。

谢谢。

【问题讨论】:

  • 我认为您出于学习原因需要手动实现排序 - 但只是指出List.sort() 将对您的列表进行排序。

标签: java algorithm sorting arraylist mergesort


【解决方案1】:

让我们使用半闭区间[beg, fin),因为这种方法用于Java、C++等的大多数内置方法中。

那么调用应该是:

jpanel4.mergeSort(jpanel4.lista, 0, jpanel4.lista.size());
//                                                      ^ no -1

现在让我们看看如何划分给定的区间。让我们使用[beg, mid)[mid, end) 间隔。如果l &gt;= r,则区间为空。

但是如果给定区间的长度为 1,它将被分成长度为 0 和 1 的两个区间,并且将递归调用 mergeSort 以对完全相同的区间进行排序。您不需要对单元素数组进行排序,它已经排序了。

所以mergeSort 应该是这样的:

    public void mergeSort(ArrayList<Integer> list, int beg, int fin){
        if(beg + 1 < fin){
        //     ^^^ added +1 to ensure we sort only intervals with length >= 2
            int mid = (beg+fin)/2;
            mergeSort(list, beg, mid);
            mergeSort(list, mid, fin);
            //                 ^ no +1
            Merge(list, beg, mid, fin);
        }
    }

Merge也有错误:

    public void Merge(ArrayList<Integer> list, int beg, int mid, int fin){

        // ...

        while (i < left.size() && j < right.size()) {
            if (left.get(i) <= right.get(j)) {
            //                           ^ you should compare left[i] and right[j]
                list.set(k, left.get(i));
                i++;
                
            } else {
                list.set(k, right.get(j));
                j++;
            }
            
            k++;
        }

        // ...

     }

【讨论】:

  • 感谢您的解释,它工作得更好,但它还没有正确排序列表;(
  • @SirHauneXXIV 更新了答案,Merge 中有一个错误。这是一个游乐场:tpcg.io/2qSaOV1c
【解决方案2】:
Check my version of merge sort using array list hope it help you    : https://github.com/murari99732/solutionleetcode-adventofcode/blob/master/PracticeAlgo/src/LeetCode/MergeSort.java

public static void mergeSort(List<Integer> arr, int start, int end) {
        if (start != end) {
            int mid = (start + end) / 2;
            mergeSort(arr, start, mid);
            mergeSort(arr, mid + 1, end);
            merge(arr, start, mid, end);
        }
    }

    private static void merge(List<Integer> arr, int start, int mid, int end) {
        int i = start;
        int j = mid + 1;
        int k = 0;

        int[] temp = new int[end - start + 1];

        while ((i <= mid) && (j <= end)) {
            if (arr.get(i) < arr.get(j))
                temp[k++] = arr.get(i++);
            else
                temp[k++] = arr.get(j++);
        }

        while (i <= mid) {
            temp[k++] = arr.get(i++);
        }

        while (j <= end) {
            temp[k++] = arr.get(j++);
        }

        for (i = start; i <= end; i++) {
            arr.remove(i);
            int e = temp[i - start];
            arr.add(i, e);
        }
    }

【讨论】:

    【解决方案3】:

    主要错误是一个简单的错字:if (left.get(i) &lt;= right.get(i)) { 应该是:

        if (left.get(i) <= right.get(j)) {
    

    数组索引值和边界也有问题:应该包括begmid 索引,而应该排除fin(结束?)。这也消除了对+1 / -1 调整的需要。

    int mid = (beg + fin) / 2; 中有一个更微妙的错误:计算这个和可能会溢出非常大的数组。最好写:

        int mid = beg + (fin - beg) / 2;
    

    纠正这些问题后,您可以删除 try 块。

    这是修改后的版本:

    public void mergeSort(ArrayList<Integer> list, int beg, int fin) {
        if (fin - beg >= 2) {
            int mid = beg + (fin - beg) / 2;
            mergeSort(list, beg, mid);
            mergeSort(list, mid, fin);
            Merge(list, beg, mid, fin);
        }
    }
    
    public void Merge(ArrayList<Integer> list, int beg, int mid, int fin) {
        ArrayList<Integer> left = new ArrayList<Integer>(list.subList(beg, mid));
        ArrayList<Integer> right = new ArrayList<Integer>(list.subList(mid, fin));
        
        int i = 0;
        int j = 0;
        int k = beg;
        
        while (i < left.size() && j < right.size()) {
            if (left.get(i) <= right.get(j)) {
                list.set(k, left.get(i++));
            } else {
                list.set(k, right.get(j++));
            }
            k++;
        }
        
        while (i < left.size()) {
            list.set(k, left.get(i++));
            k++;
        }
    
        while (j < right.size()) {
            list.set(k, right.get(j++));
            k++;
        }
    }
    

    你可以用jpanel4.mergeSort(jpanel4.lista, 0, jpanel4.lista.size());调用这个方法

    请注意,Merge 可以简化,因为最后一个循环是多余的,right 中的其余元素已经在 list 的末尾。事实上,没有必要保存右边部分的元素,因为它们总是被复制到较低或相等的索引值。

    这是一个简化版:

    public void Merge(ArrayList<Integer> list, int beg, int mid, int fin) {
        ArrayList<Integer> left = new ArrayList<Integer>(list.subList(beg, mid));
        
        for (int i = 0, j = mid, k = beg; i < left.size(); k++) {
            if (j >= fin || left.get(i) <= list.get(j)) {
                list.set(k, left.get(i++));
            } else {
                list.set(k, list.get(j++));
            }
        }
    }
    

    【讨论】:

    • 非常感谢,我会执行建议(是的,“fin”在西班牙语中是“end” jeje)
    猜你喜欢
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多