我可以将算法作为参数传递给java吗?

时间:2017-04-23 00:33:31

标签: java sorting methods merge quicksort

我正在对排序算法进行一些测量测试。

我创建了这个方法来计算选择排序需要订购数组的时间

public static double timeToSelectionSort(Double[] arrayOfNumbers) {

      double timeToSelectionSort =0;
  Stopwatch stopwatch = new Stopwatch();

  Selection.sort(arrayOfNumbers);

  timeToSelectionSort = stopwatch.elapsedTime(); 

  return   timeToSelectionSort;
  }

问题是我需要为我的所有排序算法(插入,选择,快速排序,合并排序......)创建此方法。

有没有办法将这些算法作为此方法的参数传递?

4 个答案:

答案 0 :(得分:6)

是的,绝对的。这就是所谓的Strategy Pattern。基本上,创建一个接口,让每个算法都是一个实现接口的类,并使参数类型为参数(我在这里使用C#约定)

public interface SortingAlgo {
  void sort(...);
}

public class QuickSort implements SortingAlgo {
  public void sort(...) {
    ...
  }
}

public void methodYouWantToAcceptAlgo(SortingAlgo algo) {
  ...
}

答案 1 :(得分:1)

  1. 如果您的排序算法全部在不同的类中实现,请使用要调用的方法创建一个接口,并让所有类实现该接口。
    例如。这就是List是具有不同性能特征的多个实现的接口的方式。

    public interface Sort {
        void sort(Double[]);
    }
    public class Selection implements Sort {
        // code here
    }
    public static double timeToSort(Double[] input, Sort sort) {
        Stopwatch stopwatch = new Stopwatch();
        sort.sort(input);
        return stopwatch.elapsedTime();
    }
    public static void test(Double[] input) {
        System.out.println(timeToSort(input, new Selection()));
    }
    
  2. 如果排序算法都是静态方法,请使用Consumer<Double[]>接口,并使用Java 8方法引用提供实现。

    public class Sorts {
        public static void selection(Double[] input) {
            // code here
        }
    }
    public static double timeToSort(Double[] input, Consumer<Double[]> sort) {
        Stopwatch stopwatch = new Stopwatch();
        sort.accept(input);
        return stopwatch.elapsedTime();
    }
    public static void test(Double[] input) {
        System.out.println(timeToSort(input, Sorts::selection));
    }
    
  3. 如果您的排序方法并非都共享相同的签名,请使用lambda表达式。这是#2的变体。

    public static void test(Double[] input) {
        System.out.println(timeToSort(input, (a) -> Sorts.selection(a)));
    }
    

答案 2 :(得分:0)

战略模式在这种情况下非常有用。

Strategy Pattern

  • 定义一系列算法,封装每个算法并制作它们 互换。策略让算法独立于 使用它的客户

  • 算法可以互换使用以改变应用程序 不改变其架构的行为。

  • 通过单独封装算法,新算法符合要求 可以很容易地引入相同的界面。

其他简单方法是使用Lambda Function

答案 3 :(得分:0)

正如EJoshuaS所说,你正在询问strategy pattern。策略模式的目的是准确解决您所描述的问题 - 您希望应用某些操作,但您不一定知道 在编译时操作,因此您定义了一个&#34;策略&#34;界面,允许您将调用策略的代码与定义策略的代码分开。

在您的情况下,您希望对数组进行排序,但希望将其与哪个算法实际执行排序操作分离。因此,首先定义一个接口来描述排序:

/** Interface responsible for sorting an array of doubles. */
@FunctionalInterface // we'll come back to this
public interface Sorter {
  /** Sorts the input array in ascending order. */
  void sort(double[] arr);
}

现在我们有了一个接口,我们可以编写使用该接口的代码,尽管不知道实现的内容(例如冒泡排序,快速排序等):

/** Given an array and a sorting strategy to apply, prints the sorted array. */
public static void printSorted(double[] arr, Sorter sorter) {
  sorter.sort(arr);
  System.out.println(Arrays.toString(arr));
}

太好了,我们已经完成了!主要是......现在我们需要创建Sorter的一些实现来调用printSorted()。虽然我将实现本身留给您,但样板文件看起来像:

/** Sorter strategy applying the bubble-sort algorithm. */
public class BubbleSorter implements Sorter {
  @Override
  public void sort(double[] arr) {
    // TODO
  }
}

如果您有一个或多个Sorter实施,则可以调用printSorted()

printSorted(new double[] {5.0, 3.0, 10.0}, new BubbleSorter());

任务(打印已排序的数组)现在与要排序的数组要分离的排序策略分离,您可以轻松替换不同的策略。

但是等等,Java 8怎么样?

Lambda和一般的函数式编程本质上是应用策略模式的一种很好的语法(原谅粗略的过度简化),并且事实证明它们对于这类任务非常有效。

我将Sorter注释为上面的@FunctionalInterface,注意到该接口旨在用于构造lambda表达式。任何需要double[]并且不返回任何内容的操作都可以作为lambda传递到我们的printSorted()函数中。例如,我们可以使用Arrays.sort()作为我们的策略:

printSorted(..., d -> Arrays.sort(d));

更好的方法是在这里使用method referenceArrays::sort),但为了清晰起见,我使用了lambda。

您可能会注意到Sorter看起来很像Consumer<double[]>。在实践中, Consumer,因此我们可以删除该界面并让printSorted()获取Consumer<double[]>。您应该更喜欢(重用Consumer或定义自己的界面)主要是偏好问题,但在different contexts both are reasonable choices中。