当前位置: 首页 > 知识库问答 >
问题:

如何在Java中修复合并排序算法并从函数返回排序数组

仲孙小云
2023-03-14

我在Java中实现合并排序算法时遇到了一个问题:我做过合并排序算法,但它不能产生正确的结果。我还从函数中返回排序列表。我怎么也能做到这一点?

下面是我定义的合并排序算法。

合并排序方法:

public static void mergeSort(ArrayList<Person> personList, Comparator<Person> compTr) {
    ArrayList<Person> helper = new ArrayList<Person>();
    mergeSort(personList, helper, 0, personList.size() - 1, compTr);
}

MergeSort函数:

private static void mergeSort(ArrayList<Person> list, 
                              ArrayList<Person> helper, 
                              int low, 
                              int high, 
                              Comparator<Person> compTr) {
    if (low < high) {
        int middle = (low + high) / 2;
        mergeSort(list, helper, low, middle, compTr); //sort left half
        mergeSort(list, helper, middle + 1, high, compTr); //sort right half
        merge(list, helper, low, middle, high, compTr); // merge
    }
}

合并算法:

private static void merge(ArrayList<Person> list, 
                          ArrayList<Person> helper, 
                          int low, 
                          int middle, 
                          int high,
                          Comparator<Person> compTr) {
    //This loop throws Exception
    for (int i = low; i < high + 1; i++) {
        helper.add(i, list.get(i));
    }

    int helperLeft = low;
    int helperRight = middle + 1;
    int current = low;

    while (helperLeft < middle && helperRight < high) {
        if (isGreaterThan(helper.get(helperLeft), helper.get(helperRight), compTr)) {
            list.set(current, helper.get(helperLeft));
            helperLeft++;
        } else {
            list.set(current, helper.get(helperRight));
            helperRight++;
        }
        current++;
    }

    //Copy remaining elements
    int remaining = middle - helperLeft;
    for (int j = 0; j <= remaining; j++) {
        list.set(current + j, helper.get(helperLeft + j));
    }

    // RETURN LIST(list) _-> TO DO 
}

实现比较器功能

public static boolean isGreaterThan(Person helperLeft, Person helperRight, Comparator<Person> compTr) {
    return greaterThan(compTr, helperLeft, helperRight);
}

private static boolean greaterThan(Comparator comp, Person x, Person y) {
    return comp.compare(x, y) > 0;
}

我该怎么做?

共有3个答案

欧阳飞
2023-03-14

这就是我的答案

我更改了代码

 while(helperLeft < middle && helperRight < high) {

 while(helperLeft <= middle && helperRight <= high) {
穆乐逸
2023-03-14

无需返回已排序的数组:数组已就地排序。

然而,请注意这些问题:

>

  • 辅助数组应该分配一个初始大小等于要排序的数组的大小。这避免了helper.add(i,list.get(i));在辅助数组中间不断插入额外元素的问题。这是非常低效的:它需要O(n*log(n))额外的空间而不仅仅是O(n),并且时间复杂度为O(nnlog(n)),比插入排序更糟糕。

    您可以使用

      ArrayList<Person> helper = new ArrayList<Person>(personList);
    

    您可以使用helper.set(i,list.get(i))保存数组元素。

    合并中的for循环应迭代到并包括上界:

      while (helperLeft <= middle && helperRight <= high) 
    

    包含上限的约定令人困惑且容易出错,排除上限要简单得多,因为它消除了-1/1调整的需要。

    以下是修改后的版本:

    public static void mergeSort(ArrayList<Person> personList, Comparator<Person> compTr) {
        ArrayList<Person> helper = new ArrayList<Person>(personList);
        mergeSort(personList, helper, 0, personList.size(), compTr);
    }
    
    private static void mergeSort(ArrayList<Person> list, 
                                  ArrayList<Person> helper, 
                                  int low, 
                                  int high, 
                                  Comparator<Person> compTr) {
        if (high - low >= 2) {
            int middle = low + (high - low) / 2;
            mergeSort(list, helper, low, middle, compTr); //sort left half
            mergeSort(list, helper, middle, high, compTr); //sort right half
            merge(list, helper, low, middle, high, compTr); // merge
        }
    }
    
    private static void merge(ArrayList<Person> list, 
                              ArrayList<Person> helper, 
                              int low, 
                              int middle, 
                              int high,
                              Comparator<Person> compTr) {
    
        for (int i = low; i < high; i++) {
            helper.set(i, list.get(i));
        }
    
        int helperLeft = low;
        int helperRight = middle;
        int current = low;
    
        while (helperLeft < middle && helperRight < high) {
            if (isGreaterThan(helper.get(helperLeft), helper.get(helperRight), compTr)) {
                list.set(current, helper.get(helperLeft));
                helperLeft++;
            } else {
                list.set(current, helper.get(helperRight));
                helperRight++;
            }
            current++;
        }
    
        // Copy remaining elements
        while (helperLeft < middle) {
            list.set(current, helper.get(helperLeft));
            helperLeft++;
            current++;
        }
    }
    

  • 鱼志诚
    2023-03-14

    我无法从合并函数中获取作为列表的返回值

    如果我理解正确,您正在寻找返回排序列表的方法。但在您的实现中,您试图对原始列表进行排序<这意味着您在调用合并函数时已经有了一个指向结果排序列表的变量:调用时用作参数的变量

    public static void mergeSort(ArrayList<Person> personList, Comparator<Person> compTr)
    

    例如,如果您的人员在名为“list”的ArrayList中,则您正在对此“list”进行排序。

        ArrayList<Person> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(new Person());
        }
        System.out.println(list);
        mergeSort(list, Comparator.<Person>naturalOrder());
        System.out.println(list);
    

    有关更多信息,您使用的被称为inout参数,例如您将输入赋予函数,并通过该参数接收其输出。

    正如评论中指出的,代码还有其他问题。我怀疑这里有一个错误(

    (helperRight <= high)
    
    

    另一个原因是您在就地合并排序中使用了临时列表。

    这里可以找到一个工作示例:如何使用合并排序算法就地排序?

     类似资料:
    • 我写了3个方法来实现递归合并排序,参数数量有限(没有aux、lo、mid、hi)。我认为我的工作是这样的,但它并没有返回一个排序数组,尽管它在运行时没有任何编译错误。我已经摆弄了4个小时,似乎无法弄清楚我做错了什么,没有合并一个有序数组。我只从我的助教那里得到了非常模糊的输入,并且能够修复我正在遇到的一些问题,但是该方法仍然没有对项数组进行排序。欢迎任何关于我在这里做错了什么的建议。谢谢!

    • 问题是关于从16:43到23:34的视频中的合并排序http://youtu.be/M814OagXWTI?t=16m43s 在退出左/右排序合并递归后,我不清楚我们是如何合并回这些子数组的。让我们从最底部开始,当我们的元素被分成两个子数组时,一个左子数组称为B,一个右子数组称为C。在16:43左右,我们跳转到合并函数,对数组B和C进行排序,这两个数组只有8和3。合并排序函数(下面的代码)基本上通

    • 我知道合并排序算法的基本概念,但是当涉及到通过递归实现它时,我很难理解它是如何工作的。据我所知,合并排序函数将我们当前的数组分成两半,并使用递归我们一直这样做,直到每边只剩下一个元素。 如果我们的数组是{38、27、43、3、9、82、10},那么我们的递归将从使用子数组(原始数组的左侧)调用自身开始,并每次重复该过程,将数组减半并存储最左侧,直到达到1个元素: 然后在我们的第二个子例程中,我们继

    • 我想用Javascript实现合并排序作为一种学习经验。我有mergeSort(unsortedArray)函数,它接受一个未经排序的数组,并使用合并排序策略对其进行排序。mergeSort()调用merge(leftArray,rightArray),后者将两个数组合并在一起,得到一个数组。 我认为问题出在merge()函数上。在数组[8,8,7,5,4,6,3,2,1,5,9,8,7,6,5,

    • 我有三个排序数组,如下所示 这些数组根据数组中每个对象的名称属性进行排序。下面是我从Java转换为合并两个排序数组的方法 这里是两个数组的工作小提琴http://jsfiddle.net/euRn5/.什么是最好的方法来实现相同的n个数组,我目前的想法是一个接一个,合并它与以前合并到最后项目,像n=i的东西。这是最好的方法吗?

    • 对于合并排序,我写了这样的代码:我已经测试了合并功能,工作正常。但是在mergeSort函数中,我不能处理数组。它返回与输入列表相同的列表。