簡體   English   中英

用於ArrayLists的Java遞歸MergeSort

[英]Java Recursive MergeSort for ArrayLists

我的mergesort函數一直存在問題,因為我無法在將其輸入程序時對一系列整數或字符串進行排序。 我有一個調用項目的外部類,但它根本不對數字/字符串進行排序。 下面兩種方法,我不知道問題出在哪里。 數字是隨機輸入的。

碼:

/**
     * Takes in entire vector, but will merge the following sections together:
     * Left sublist from a[first]..a[mid], right sublist from a[mid+1]..a[last].
     * Precondition: each sublist is already in ascending order
     *
     * @param a
     *            reference to an array of integers to be sorted
     * @param first
     *            starting index of range of values to be sorted
     * @param mid
     *            midpoint index of range of values to be sorted
     * @param last
     *            last index of range of values to be sorted
     */
    private void merge(ArrayList<Comparable> a, int first, int mid, int last) {
        int x;
        int i;
        ArrayList<Comparable> left = new ArrayList<Comparable>();
        ArrayList<Comparable> right = new ArrayList<Comparable>();
        mergeSort(a,first,mid);
        for(i = 0; i < a.size() - mid; i++){
            left.add(i,a.get(i));
            a.remove(i);
        }
        mergeSort(a,mid,last);
        for (x = mid; x < a.size(); x++) {
            right.add(x,a.get(x));
            a.remove(x);
        }
        if ((left.get(i).compareTo(right.get(x))) > 0) {
            i++;
            a.add(i);
        } else if (i < x) {
            x++;
            a.add(x);
        }


        System.out.println();
        System.out.println("Merge");
        System.out.println();

    }

    /**
     * Recursive mergesort of an array of integers
     *
     * @param a
     *            reference to an array of integers to be sorted
     * @param first
     *            starting index of range of values to be sorted
     * @param last
     *            ending index of range of values to be sorted
     */
    public void mergeSort(ArrayList<Comparable> a, int first, int last) {

        int mid = (first + last)/2;
        if(first == last){

        }else if(last - first == 1){
            merge(a,first, mid ,last);              
        }else{
            last = mid;
        }


                }

我有一個調用項目的外部類,但它根本不對數字/字符串進行排序。 下面兩種方法,我不知道問題出在哪里。

第一個問題是,如果使用first = 0last = a.size()調用mergeSort方法, last = a.size()會對任何內容進行排序,因為如果last-first == 1則只調用merge

public void mergeSort(ArrayList<Comparable> a, int first, int last) {
    int mid = (first + last)/2;
    if(first == last){
    }else if(last - first == 1){
        // you only merge if last - first == 1...
        merge(a,first, mid ,last);              
    }else{
        last = mid;
    }
}

從這一點來說,我不知道你是如何嘗試實現Merge Sort算法的。 它既不是自上而下,也不是自下而上的實現。 你在merge方法中分裂,這也很奇怪。 如果您提供了偽代碼+調用public方法的方式,那么幫助您會更容易。 恕我直言,你的算法有一個真正的問題。

實際上,合並排序算法實現起來非常簡單。 為了說明這一點,我使用Deque而不是List對象編寫了這種自頂向下的合並排序算法實現

import java.util.Deque;
import java.util.LinkedList;

public class Example {

    private LinkedList<Comparable> merge(final Deque<Comparable> left, final Deque<Comparable> right) {
        final LinkedList<Comparable> merged = new LinkedList<>();
        while (!left.isEmpty() && !right.isEmpty()) {
            if (left.peek().compareTo(right.peek()) <= 0) {
                merged.add(left.pop());
            } else {
                merged.add(right.pop());
            }
        }
        merged.addAll(left);
        merged.addAll(right);
        return merged;
    }

    public void mergeSort(final LinkedList<Comparable> input) {
        if (input.size() != 1) {
            final LinkedList<Comparable> left = new LinkedList<Comparable>();
            final LinkedList<Comparable> right = new LinkedList<Comparable>();
            // boolean used to decide if we put elements
            // in left or right LinkedList
            boolean logicalSwitch = true;
            while (!input.isEmpty()) {
                if (logicalSwitch) {
                    left.add(input.pop());
                } else {
                    right.add(input.pop());
                }
                logicalSwitch = !logicalSwitch;
            }
            mergeSort(left);
            mergeSort(right);
            input.addAll(merge(left, right));
        }
    }
}

我使用了Deque因為peek() / pop()get(0)remove(0)更漂亮,但它取決於你。 如果你絕對想在這里使用ArrayList ,請遵循相應的實現。

import java.util.ArrayList;
import java.util.List;

public class Example {

    private List<Comparable> merge(final List<Comparable> left, final List<Comparable> right) {
        final List<Comparable> merged = new ArrayList<>();
        while (!left.isEmpty() && !right.isEmpty()) {
            if (left.get(0).compareTo(right.get(0)) <= 0) {
                merged.add(left.remove(0));
            } else {
                merged.add(right.remove(0));
            }
        }
        merged.addAll(left);
        merged.addAll(right);
        return merged;
    }

    public void mergeSort(final List<Comparable> input) {
        if (input.size() != 1) {
            final List<Comparable> left = new ArrayList<Comparable>();
            final List<Comparable> right = new ArrayList<Comparable>();
            boolean logicalSwitch = true;
            while (!input.isEmpty()) {
                if (logicalSwitch) {
                    left.add(input.remove(0));
                } else {
                    right.add(input.remove(0));
                }
                logicalSwitch = !logicalSwitch;
            }
            mergeSort(left);
            mergeSort(right);
            input.addAll(merge(left, right));
        }
    }
}

這兩種實現都適用於IntegerString或其他Comparable

希望能幫助到你。

有幾個問題,但重要的是你不應該在修改列表時迭代列表,即:

for (i = 0; i < a.size() - mid; i++){
    left.add(i,a.get(i));
    a.remove(i);
}

因為一旦刪除了一個元素,其他元素的索引就不一樣了......所以你添加了a不是你想象的left元素。

工作代碼如下(帶一些注釋):

 private static void merge(ArrayList<Comparable> a) {
    if (a.size()<=1) return; // small list don't need to be merged

    // SEPARATE

    int mid = a.size()/2; // estimate half the size

    ArrayList<Comparable> left = new ArrayList<Comparable>();
    ArrayList<Comparable> right = new ArrayList<Comparable>();

    for(int i = 0; i < mid; i++) left.add(a.remove(0)); // put first half part in left
    while (a.size()!=0) right.add(a.remove(0)); // put the remainings in right
    // Here a is now empty

    // MERGE PARTS INDEPENDANTLY

    merge(left);  // merge the left part
    merge(right); // merge the right part

    // MERGE PARTS

    // while there is something in the two lists
    while (left.size()!=0 && right.size()!=0) {
      // compare both heads, add the lesser into the result and remove it from its list
      if (left.get(0).compareTo(right.get(0))<0) a.add(left.remove(0));
      else                                       a.add(right.remove(0));
    }

    // fill the result with what remains in left OR right (both can't contains elements)
    while(left.size()!=0)  a.add(left.remove(0));
    while(right.size()!=0) a.add(right.remove(0));
  }

它已經在一些輸入上進行了測試......例如:

[4, 7, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11]
[0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

為了提高效率,您可以使用subList方法來避免顯式構造過多的子列表,它需要注意索引。

如果要使用Merge排序對數組進行排序,而不是自己實現排序算法,我建議使用標准Java排序算法,因為它為非基本類型實現了“ 合並排序 ”算法。

Collections.sort();

如果您想實現自己的Merge排序版本,那么您應首先查看此實現

如果您對更好地理解排序算法感興趣,我推薦這本書

一個關於Kraal實施的警告得到了勾選標記。 這是一個很棒的實現,但是Kraal的Merge排序不保留具有相同值的項的相對順序,在某些情況下,例如在排序對象時,合並排序具有其他排序算法的重要優勢,例如quicksort , 沒有。 我修改了Kraal的代碼以保留相對訂單。

private static List<Object> merge(final List<Object> left, final List<Object> right) {
            printArr("left", left);
            printArr("Right", right);
            final List<Object> merged = new ArrayList<>();
            while (!left.isEmpty() && !right.isEmpty()) {
                if(left.get(0).getValue()-right.get(0).getValue() <= 0){
                    merged.add(left.remove(0));
                } else {
                    merged.add(right.remove(0));
                }
            }
            merged.addAll(left);
            merged.addAll(right);
            return merged;
     }

 public static void mergeSort(final List<Object> input) {
     if (input.size() > 1) {
         final List<Object> left = new ArrayList<Object>();
         final List<Object> right = new ArrayList<Object>();
         boolean logicalSwitch = true;

         while (!input.isEmpty()) {
             if (logicalSwitch) {
                 left.add(input.remove(0));
             } else {
                 right.add(input.remove(input.size()/2));
             }
             logicalSwitch = !logicalSwitch;
         }
         mergeSort(left);
         mergeSort(right);
         input.addAll(merge(left, right));
     }
 }
public class MergeSort{
    public void sort(List<Integer> list){
        sortAndMerge(list, 0, list.size()-1);
    }

    public void sortAndMerge(List<Integer> list, int start, int end){
        if((end - start) >= 2){
            int mid = (end - start)/2;
            sortAndMerge(list, start, start + mid);
            sortAndMerge(list, start + mid +1, end);

            int i=start;
            int j=start + mid +1;
            while(i<j && j<=end){
                if(list.get(i) > list.get(j)){
                    list.add(i, list.remove(j));
                    i++;
                    j++;
                }else if(list.get(i) == list.get(j)){
                    list.add(i+1, list.remove(j));
                    i++;
                    j++;
                }else{
                    i++;
                }
            }  

        }else{
            if(end > start){
                if(list.get(start) > list.get(end)){
                    int endValue = list.remove(end);
                    list.add(start, endValue);
                }                
            }
        }
    }

暫無
暫無

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

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