簡體   English   中英

如何使用合並排序從大到小返回不滿足排序條件的對數?

[英]How can I return the number of pairs that do not satisfy the sorting condition from largest to smallest using merge sort?

我有一個 function public static int countBaad(int[] hs)接受一個輸入數組,我應該找出有多少數字小於它前面的數字。

例如,

如果hs = [7,3,5,4,1]答案將是 2,因為違反順序的對是 3 和 5 以及 3 和 4,因為 3 比它們小並且應該在它們之前。

如果hs = [8,5,6,7,2,1]答案將是 3,因為 5 小於 6 和 7,給我們 2,並且由於 6 也小於 7,我們將得到總共 3錯誤的對

這是我當前使用合並排序方法的代碼:

    public static int countBaad(int[] hs){
        return mergeSort(hs, hs.length);
    }

    public static int mergeSort(int[] a, int n) {
        if (n < 2) {
            return n;
        }
        int mid = n / 2;
        int[] l = new int[mid];
        int[] r = new int[n - mid];

        for (int i = 0; i < mid; i++) {
            l[i] = a[i];
        }
        for (int i = mid; i < n; i++) {
            r[i - mid] = a[i];
        }
        mergeSort(l, mid);
        mergeSort(r, n - mid);

        return merge(a, l, r, mid, n - mid);
    }
    public static int merge(int[] a, int[] l, int[] r, int left, int right) {
        int size = 0;
        int i = 0, j = 0, k = 0;
        while (i < left && j < right) {
            if (l[i] <= r[j]) {
                a[k++] = l[i++];
                size++;
            }
            else {
                a[k++] = r[j++];
                size++;
            }
        }
        while (i < left) {
            a[k++] = l[i++];
            size++;
        }
        while (j < right) {
            a[k++] = r[j++];
            size++;
        }
        return size;
    }

        

在我輸入 arrays 后,這段代碼給了我錯誤的 output

hs = [7,3,5,4,1]返回 5

hs = [8,5,6,7,2,1]返回 6

我在這里做錯了什么,有人可以糾正我嗎?

您的代碼當前正在做的是嘗試進行排序,然后簡單地返回排序數組的大小(大驚喜,給定恰當命名的size變量)。

基本上,您按降序排序,您的規范要求結果是有多少數字小於數組中后面出現的數字。 但是,在merge中,您實際上是在增加size ,而不管它們的值如何。

然后,您只返回最終合並的“大小”結果,而不返回其間所需的排序步驟的結果。

最后,也許房間里的大象是您正在執行(不必要的)排序作為副作用,但完全忽略了它。

長話短說,代碼過於復雜且容易出錯,無法實現其應有的功能。

這是一個簡單的雙 for 循環,可以達到預期的結果:

    public static int countBaad(int[] hs){
        
        int count = 0;
        for(int i = 0; i < hs.length; i++) {
            for(int j = i+1; j < hs.length; j++) {
                //compare the i'th position with all subsequent positions
                int current = hs[i];
                int other = hs[j];
                if(current < other) {
                    System.out.println("Found bad number pair: ("+current+","+other+")");
                    count++;
                }
            }
            
        }
        return count;
    }

System.out.println(countBaad(new int[]{7,3,5,4,1}));
//prints:
//Found bad number pair: (3,5)
//Found bad number pair: (3,4)
//2
System.out.println(countBaad(new int[]{8,5,6,7,2,1}));
//prints:
//Found bad number pair: (5,6)
//Found bad number pair: (5,7)
//Found bad number pair: (6,7)
//3

這更加簡潔並且沒有副作用。

編輯:

修復 mergeSort 代碼,使用額外的 sysout 日志記錄來說明算法:

    public static int mergeSort(int[] a, int n) {
        if(n==1) {
            //No sorting required, so the result should be 0.
            return 0;
        }
        int mid = n / 2;
        
        int[] l = new int[mid];
        int[] r = new int[n - mid];
        
        //'splitting the array' loops are just arraycopy, so
        // should use the native implementation:
        System.arraycopy(a, 0, l, 0, mid);
        if(n - mid >= 0) System.arraycopy(a, mid, r, 0, n - mid);
        
        //add the results from all merges, not just the last one
        int result = 0;
        result += mergeSort(l, mid);
        result += mergeSort(r, n - mid);
        result += merge(a, l, r); //there is no need to pass in the array lengths
        return result;
    }
    public static int merge(int[] a, int[] l, int[] r) {
        System.out.println("Merging "+Arrays.toString(l)+" and "+Arrays.toString(r));
        int size = 0;
        int lIdx = 0, rIdx = 0, aIdx = 0;
        while (lIdx < l.length && rIdx < r.length) {
            if (l[lIdx] >= r[rIdx]) {
                a[aIdx++] = l[lIdx++];
                //size++; //no: left was already bigger than right
            }
            else {
                //take from the right.
                //This number is bigger than all the numbers remaining on the left.
                for(int tempIdx = lIdx;tempIdx<l.length;tempIdx++) {
                    //this loop is for illustration only
                    System.out.println("  Found bad pair: (" + l[tempIdx] + "," + r[rIdx] + ")");
                }
                size+=l.length-lIdx;
                a[aIdx++] = r[rIdx++];
            }
        }
        
        //while (lIdx < left) { //NOTE that you had this condition incorrectly reversed resulting in bad merge
        //  a[aIdx++] = l[lIdx++];
        //  size++; //no, no comparisons are taking place here
        //}
        //while (rIdx < right) { //NOTE that you had this condition incorrectly reversed, resulting in bad merge
        //  a[aIdx++] = r[rIdx++];
        //  size++; //no, no comparisons are taking place here
        //}
        
        //we can also replace the above two loops with arraycopy
        // which will perform better on large arrays
        if(lIdx < left) {
            System.arraycopy(l, lIdx, a, aIdx, l.length-lIdx);
        }
        if(rIdx < right) {
            System.arraycopy(r, rIdx, a, aIdx, r.length-rIdx);
        }
        
        return size;
    }

由於您重視性能,因此應盡可能使用 System.arraycopy。 我還重命名了循環變量以使代碼更易於理解。

System.out.println(countBaad(new int[]{7,3,5,4,1}));
//prints:
//Merging [7] and [3]
//Merging [4] and [1]
//Merging [5] and [4, 1]
//Merging [7, 3] and [5, 4, 1]
//  Found bad pair: (3,5)
//  Found bad pair: (3,4)
//2
System.out.println(countBaad(new int[]{8,5,6,7,2,1}));
//prints:
//Merging [5] and [6]
//  Found bad pair: (5,6)
//Merging [8] and [6, 5]
//Merging [2] and [1]
//Merging [7] and [2, 1]
//Merging [8, 6, 5] and [7, 2, 1]
//  Found bad pair: (6,7)
//  Found bad pair: (5,7)
//3

編輯#2

要從此方法中刪除副作用(排序),可以復制輸入數組,例如簡單調用Arrays.copyOf(hs, hs.length); 並傳入結果而不是原始結果。

暫無
暫無

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

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