如何在功能性分而治之 Java 算法中实现“分”功能?

Posted

技术标签:

【中文标题】如何在功能性分而治之 Java 算法中实现“分”功能?【英文标题】:How can I implement the function "divide" in a functional Divide-And-Conquer Java algorithm? 【发布时间】: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 的情况下编译代码的。你应该先和你的教授讨论那个奇怪的签名。 【参考方案1】:

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

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

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

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

    您没有在实现中使用 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 并适当地使用结果。

以上是关于如何在功能性分而治之 Java 算法中实现“分”功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 iOS Pin It SDK 在 Pinterest 中实现 Followboard 按钮功能?

如何在 Laravel 中实现 GoogleOR-Tool?特别是对于“作为最小成本流算法的分配”(Java)

java中实现分页的常见几种方式

如何在 C++ 中实现这个数据结构

在 PL/pgSQL 中实现游标功能作为分页

如何java中实现上传头像功能?