簡體   English   中英

如何為 ArrayList 實現歸並排序?

[英]How can I implement mergesort for a ArrayList?

我有一個 ArrayList 的ArrayList排序代碼,但它沒有正確排序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++;
        }
    }
}

當我從其他 class 調用它時......

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

(合並在 jpanel4 類中)。

我將 arrays 的合並排序代碼轉換為該代碼,因為它可以與我擁有的其他代碼一起正常工作。

謝謝。

讓我們使用半閉區間[beg, fin)因為這種方法用於 Java、C++ 等的大多數內置方法中。

那么調用應該是:

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

現在讓我們看看如何划分給定的區間。 讓我們使用[beg, mid)[mid, end)間隔。 如果l >= 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++;
        }

        // ...

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

主要錯誤是一個簡單的錯字: if (left.get(i) <= right.get(i)) {應該是:

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

數組索引值和邊界也有問題:應該包括begmid索引,並且應該排除fin (結束?)。 這也消除了+1 / -1調整的需要。

int mid = (beg + fin) / 2;有一個更微妙的錯誤。 :對於非常大的 arrays,計算此總和可能會溢出。 最好寫:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM