【问题标题】:How can I implement the function "divide" in a functional Divide-And-Conquer Java algorithm?如何在功能性分而治之 Java 算法中实现“分”功能?
【发布时间】:2018-06-23 11:11:20
【问题描述】:

我正在尝试实现快速排序算法的功能版本。 我的教授让我留下这个作为签名:

public static <T, R> List<T> myQuickSort(Function<List<T>, Boolean> trivial, 
        Function<List<T>, T> solve, Function<List<T>, R> divide, 
        Function<T, List<R>> combine, List<T> input)

我创建了一个名为 Pair 的辅助类,如下所示:

public class Pair {

List<Integer> first; 
List<Integer> second; 

Pair(List<Integer> f, List<Integer> s) {
    first = f; 
    second = s; 
}
public static Pair div(List<Integer> input) {
    int pivot = (int) input.get(0); 
    List<Integer> a = new ArrayList<Integer>();
    List<Integer> b = new ArrayList<Integer>();
    for(int i=1; i<input.size(); i++) {
        if(input.get(i) < pivot) {
            a.add(input.get(i)); 
        } else {
            b.add(input.get(i)); 
        }
    }
    return new Pair(a, b); 
}

} 我快完成了,但我无法弄清楚如何在输入数组的单个分区上递归工作。我试着这样做:

if(trivial.apply(input)) {
        solve.apply(input); 
    } else {
        output = myQuickSort(trivial, solve, divide, combine, 
                (List<T>) divide.apply(input).first); 
        output.add(input.get(0)); 
        output.addAll(myQuickSort(trivial, solve, divide, combine, 
                (List<T>) divide.apply(input).second)); 
        return output; 
    }
    return output;

但我现在卡住了。 你们中的任何人都可以告诉我哪里错了和/或我怎样才能更好地实施我的解决方案? 这也是主要的,如果它可以帮助:

Function<List<Integer>, Boolean> trivial = (a) -> a.size()==1; 
    Function<List<Integer>, Pair> divide = (a) -> Pair.div(input); 
    Function<Pair, List<Integer>> combine = 
            (a) -> Stream.concat(a.first.stream(), a.second.stream()).
            collect(Collectors.toList());
    Function<List<Integer>, Integer> solve = (a) -> a.get(0); 
    ArrayList<Integer> output = myQuickSort(trivial, solve, divide, combine, input);

【问题讨论】:

  • 签名不是有bug吗?如果combine 的类型是Function&lt;R, List&lt;T&gt;&gt;,对我来说会更有意义。
  • 我做了一些修改,现在这是签名:“public static List myQuickSort(Function, Boolean> trivial, Function , List> solve, Function, R> divide, Function> combine, List input)" 快速排序大多有效,但有一个小错误:例如,如果我给出 {70, 100, 72, 200, 57},它会返回 {52, 700, 100, 72, 200}
  • div 返回三个列表而不是一对列表会更简单、更有效:class SplitByPivot { List&lt;T&gt; equal, less, greater; }(不要忘记枢轴可以在输入中多次出现。 ) 我很确定这个错误是在你隐式处理枢轴作为Pair 中的一个棘手的特殊情况的方式中。 equal 字段将让您无需技巧地表达算法。
  • 等等——你说你的教授要求你保留那个签名,现在你改了?甚至您的更改签名也存在根本问题,即 调用者 决定 R 是什么,而不是方法。因此,您不能假设它始终是Pair。甚至不清楚你是如何在隐含假设 RPair 的情况下编译代码的。你应该先和你的教授讨论那个奇怪的签名。

标签: java algorithm lambda functional-programming quicksort


【解决方案1】:

提出了很多问题。所以我能做的就是解决问题。

  1. 我假设在您的 myQuickSort 签名中,combine 的类型已交换了 R 和 T。如果我是对的,我会发现这个签名很奇怪,如下所述。

  2. 代码中的“solve.apply()”行对返回没有任何作用。由于您不使用对该函数的调用返回,因此我无法确定“解决”的目的是什么。或许你可以澄清一下。结果,您的最后一个“返回输出”不会返回任何内容。在下面的讨论中,我忽略了“解决”。

  3. 您在 main 中实现的“组合”不必要地使用了流。 List.addAll() 可以解决问题。

  4. 您没有在实现中使用 combine 函数。

我的问题是关于你的教授给你的签名。在我看来,R 是一个代表一分为二的列表的对象。 R 将包括第一个和第二个列表,以及您所说的“枢轴”。然后,Combine 接受一个 R 并将这三个部分组合成一个列表。由于 R、divide 和 combine 的实现是由 myQuickSort 的调用者完成的,它们将处理正在排序的对象的比较(您的实现中的整数),因此 myQuickSort 不必知道正在排序的对象的类型排序。

如果我是对的,那么在我看来,您的 R 实现(称为 Pair)应该存储枢轴。然后,您的 combine 实现将结合 first、pivot 和 second。除或组合都会调用 myQuickSort: 无所谓。你有分工,这很好。

myQuickSort 然后将是:

if (trivial(input))
    return input;    // Remember I am ignoring solve()
else {
    R r = divide.apply(input);
    return combine.apply(r);
}

因此,除或组合的实现(在您的情况下是除法)通过为已划分列表的两半中的每一半调用 myQuickSort 来提供递归。

如果我在上面是对的,这是一个奇怪的签名。提供的函数必须了解 QuickSort 实现。如果 R 被定义为具有 myQuickSort 可以操作分割数组的方法,则情况并非如此。这意味着,与其简单地在静态方法签名中使用 R,不如使用“R extends DivObject”,其中 DivObject 是定义 myQuickSort 可以调用的方法的接口(或类)。我会让 DivObject 有一个 getFirst() 方法和一个 getSecond() 方法,它们返回相应的列表,以便 myQuickSort 可以在这两个列表上调用自己。它还需要像 setFirst() 和 setSecond() 这样的方法,将排序后的列表放回 R 中,以便 combine 可以组合它们(因为 combine 仅将 R 作为参数)。

希望这会有所帮助。

【讨论】:

  • solve() 应该尝试替换“return”语句,但我现在注意到它没用。关于签名,是的,这很奇怪,这就是我遇到这个困难的原因
  • 我尝试了你的方法,但是看起来“Pair”的第二部分没有被触及。你知道为什么吗?
  • 我真的无法调试你的代码。我的建议并不是唯一需要的改变。正如我所说,divide 或 combine 函数都需要在 first 和 second 上调用 myQuickSort 并适当地使用结果。
猜你喜欢
  • 2016-04-04
  • 1970-01-01
  • 2021-04-07
  • 2020-07-31
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多