二十一、数组(6)

本章概要

  • 数组排序
  • Arrays.sort的使用
  • 并行排序
  • binarySearch二分查找
  • parallelPrefix并行前缀

数组排序

根据对象的实际类型执行比较排序。一种方法是为不同的类型编写对应的排序方法,但是这样的代码不能复用。

编程设计的一个主要目标是“将易变的元素与稳定的元素分开”,在这里,保持不变的代码是一般的排序算法,但是变化的是对象的比较方式。因此,使用策略设计模式而不是将比较代码放入许多不同的排序源码中。使用策略模式时,变化的代码部分被封装在一个单独的类(策略对象)中。

您将一个策略对象交给相同的代码,该代码使用策略模式来实现其算法。通过这种方式,您将使用相同的排序代码,使不同的对象表达不同的比较方式。

Java有两种方式提供比较功能。第一种方法是通过实现 java.lang.Comparable 接口的原生方法。这是一个简单的接口,只含有一个方法 compareTo()。该方法接受另一个与参数类型相同的对象作为参数,如果当前对象小于参数,则产生一个负值;如果参数相等,则产生零值;如果当前对象大于参数,则产生一个正值。

这里有一个类,它实现了 Comparable 接口并演示了可比性,而且使用Java标准库方法 Arrays.sort():

ArrayShow.java

package com.example.test;

import java.util.*;

public interface ArrayShow {
    static void show(Object[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(boolean[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(byte[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(char[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(short[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(int[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(long[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(float[] a) {
        System.out.println(Arrays.toString(a));
    }

    static void show(double[] a) {
        System.out.println(Arrays.toString(a));
    }

    // Start with a description:
    static void show(String info, Object[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, boolean[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, byte[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, char[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, short[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, int[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, long[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, float[] a) {
        System.out.print(info + ": ");
        show(a);
    }

    static void show(String info, double[] a) {
        System.out.print(info + ": ");
        show(a);
    }
}

CompType.java

package com.example.test;

import java.util.Arrays;
import java.util.SplittableRandom;

import static com.example.test.ArrayShow.show;

public class CompType implements Comparable<CompType> {
    private static int count = 1;
    private static SplittableRandom r = new SplittableRandom(47);
    int i;
    int j;

    public CompType(int n1, int n2) {
        i = n1;
        j = n2;
    }

    public static CompType get() {
        return new CompType(r.nextInt(100), r.nextInt(100));
    }

    public static void main(String[] args) {
        CompType[] a = new CompType[12];
        Arrays.setAll(a, n -> get());
        show("Before sorting", a);
        Arrays.sort(a);
        show("After sorting", a);
    }

    @Override
    public String toString() {
        String result = "[i = " + i + ", j = " + j + "]";
        if (count++ % 3 == 0) {
            result += "\n";
        }
        return result;
    }

    @Override
    public int compareTo(CompType rv) {
        return (i < rv.i ? -1 : (i == rv.i ? 0 : 1));
    }
}

在这里插入图片描述

当您定义比较方法时,您有责任决定将一个对象与另一个对象进行比较意味着什么。这里,在比较中只使用i值和j值将被忽略。

get() 方法通过使用随机值初始化CompType对象来构建它们。在 main() 中,get()Arrays.setAll() 一起使用,以填充一个 CompType类型 数组,然后对其排序。如果没有实现 Comparable接口,那么当您试图调用 sort() 时,您将在运行时获得一个 ClassCastException 。这是因为 sort() 将其参数转换为 Comparable类型

现在假设有人给了你一个没有实现 Comparable接口 的类,或者给了你一个实现 Comparable接口 的类,但是你不喜欢它的工作方式而愿意有一个不同的对于此类型的比较方法。为了解决这个问题,创建一个实现 Comparator 接口的单独的类(在集合一章中简要介绍)。它有两个方法,compare()equals()。但是,除了特殊的性能需求外,您不需要实现 equals(),因为无论何时创建一个类,它都是隐式地继承自 ObjectObject 有一个equals()。您可以只使用默认的 Object equals() 来满足接口的规范。

集合类(注意复数;我们将在下一章节讨论它) 包含一个方法 reverseOrder(),它生成一个来 Comparator(比较器)反转自然排序顺序。这可以应用到比较对象:

import java.util.Arrays;
import java.util.Collections;

import static com.example.test.ArrayShow.show;

public class Reverse {
    public static void main(String[] args) {
        CompType[] a = new CompType[12];
        Arrays.setAll(a, n -> CompType.get());
        show("Before sorting", a);
        Arrays.sort(a, Collections.reverseOrder());
        show("After sorting", a);
    }
}

在这里插入图片描述

您还可以编写自己的比较器。这个比较CompType对象基于它们的j值而不是它们的i值:

import java.util.Arrays;
import java.util.Comparator;

import static com.example.test.ArrayShow.show;

class CompTypeComparator implements Comparator<CompType> {
    @Override
    public int compare(CompType o1, CompType o2) {
        return (o1.j < o2.j ? -1 : (o1.j == o2.j ? 0 : 1));
    }
}

public class ComparatorTest {
    public static void main(String[] args) {
        CompType[] a = new CompType[12];
        Arrays.setAll(a, n -> CompType.get());
        show("Before sorting", a);
        Arrays.sort(a, new CompTypeComparator());
        show("After sorting", a);
    }
}

在这里插入图片描述

Arrays.sort 的使用

使用内置的排序方法,您可以对实现了 Comparable 接口或具有 Comparator 的任何对象数组 或 任何原生数组进行排序。这里我们生成一个随机字符串对象数组并对其排序:

ConvertTo.java

package com.example.test;

public interface ConvertTo {
    static boolean[] primitive(Boolean[] in) {
        boolean[] result = new boolean[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i]; // Autounboxing
        }
        return result;
    }

    static char[] primitive(Character[] in) {
        char[] result = new char[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static byte[] primitive(Byte[] in) {
        byte[] result = new byte[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static short[] primitive(Short[] in) {
        short[] result = new short[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static int[] primitive(Integer[] in) {
        int[] result = new int[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static long[] primitive(Long[] in) {
        long[] result = new long[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static float[] primitive(Float[] in) {
        float[] result = new float[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static double[] primitive(Double[] in) {
        double[] result = new double[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    // Convert from primitive array to wrapped array:
    static Boolean[] boxed(boolean[] in) {
        Boolean[] result = new Boolean[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i]; // Autoboxing
        }
        return result;
    }

    static Character[] boxed(char[] in) {
        Character[] result = new Character[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static Byte[] boxed(byte[] in) {
        Byte[] result = new Byte[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static Short[] boxed(short[] in) {
        Short[] result = new Short[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static Integer[] boxed(int[] in) {
        Integer[] result = new Integer[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static Long[] boxed(long[] in) {
        Long[] result = new Long[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static Float[] boxed(float[] in) {
        Float[] result = new Float[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }

    static Double[] boxed(double[] in) {
        Double[] result = new Double[in.length];
        for (int i = 0; i < in.length; i++) {
            result[i] = in[i];
        }
        return result;
    }
}

Rand.java

package com.example.test;

import java.util.*;
import java.util.function.*;
import static com.example.test.ConvertTo.primitive;

public interface Rand {
    int MOD = 10_000;

    class Boolean implements Supplier<java.lang.Boolean> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Boolean get() {
            return r.nextBoolean();
        }

        public java.lang.Boolean get(int n) {
            return get();
        }

        public java.lang.Boolean[] array(int sz) {
            java.lang.Boolean[] result =
                    new java.lang.Boolean[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pboolean {
        public boolean[] array(int sz) {
            return primitive(new Boolean().array(sz));
        }
    }

    class Byte
            implements Supplier<java.lang.Byte> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Byte get() {
            return (byte) r.nextInt(MOD);
        }

        public java.lang.Byte get(int n) {
            return get();
        }

        public java.lang.Byte[] array(int sz) {
            java.lang.Byte[] result =
                    new java.lang.Byte[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pbyte {
        public byte[] array(int sz) {
            return primitive(new Byte().array(sz));
        }
    }

    class Character
            implements Supplier<java.lang.Character> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Character get() {
            return (char) r.nextInt('a', 'z' + 1);
        }

        public java.lang.Character get(int n) {
            return get();
        }

        public java.lang.Character[] array(int sz) {
            java.lang.Character[] result =
                    new java.lang.Character[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pchar {
        public char[] array(int sz) {
            return primitive(new Character().array(sz));
        }
    }

    class Short
            implements Supplier<java.lang.Short> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Short get() {
            return (short) r.nextInt(MOD);
        }

        public java.lang.Short get(int n) {
            return get();
        }

        public java.lang.Short[] array(int sz) {
            java.lang.Short[] result =
                    new java.lang.Short[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pshort {
        public short[] array(int sz) {
            return primitive(new Short().array(sz));
        }
    }

    class Integer
            implements Supplier<java.lang.Integer> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Integer get() {
            return r.nextInt(MOD);
        }

        public java.lang.Integer get(int n) {
            return get();
        }

        public java.lang.Integer[] array(int sz) {
            int[] primitive = new Pint().array(sz);
            java.lang.Integer[] result =
                    new java.lang.Integer[sz];
            for (int i = 0; i < sz; i++) {
                result[i] = primitive[i];
            }
            return result;
        }
    }

    class Pint implements IntSupplier {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public int getAsInt() {
            return r.nextInt(MOD);
        }

        public int get(int n) {
            return getAsInt();
        }

        public int[] array(int sz) {
            return r.ints(sz, 0, MOD).toArray();
        }
    }

    class Long implements Supplier<java.lang.Long> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Long get() {
            return r.nextLong(MOD);
        }

        public java.lang.Long get(int n) {
            return get();
        }

        public java.lang.Long[] array(int sz) {
            long[] primitive = new Plong().array(sz);
            java.lang.Long[] result =
                    new java.lang.Long[sz];
            for (int i = 0; i < sz; i++) {
                result[i] = primitive[i];
            }
            return result;
        }
    }

    class Plong implements LongSupplier {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public long getAsLong() {
            return r.nextLong(MOD);
        }

        public long get(int n) {
            return getAsLong();
        }

        public long[] array(int sz) {
            return r.longs(sz, 0, MOD).toArray();
        }
    }

    class Float
            implements Supplier<java.lang.Float> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Float get() {
            return (float) trim(r.nextDouble());
        }

        public java.lang.Float get(int n) {
            return get();
        }

        public java.lang.Float[] array(int sz) {
            java.lang.Float[] result =
                    new java.lang.Float[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pfloat {
        public float[] array(int sz) {
            return primitive(new Float().array(sz));
        }
    }

    static double trim(double d) {
        return
                ((double) Math.round(d * 1000.0)) / 100.0;
    }

    class Double implements Supplier<java.lang.Double> {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public java.lang.Double get() {
            return trim(r.nextDouble());
        }

        public java.lang.Double get(int n) {
            return get();
        }

        public java.lang.Double[] array(int sz) {
            double[] primitive =
                    new Rand.Pdouble().array(sz);
            java.lang.Double[] result =
                    new java.lang.Double[sz];
            for (int i = 0; i < sz; i++) {
                result[i] = primitive[i];
            }
            return result;
        }
    }

    class Pdouble implements DoubleSupplier {
        SplittableRandom r = new SplittableRandom(47);

        @Override
        public double getAsDouble() {
            return trim(r.nextDouble());
        }

        public double get(int n) {
            return getAsDouble();
        }

        public double[] array(int sz) {
            double[] result = r.doubles(sz).toArray();
            Arrays.setAll(result,
                    n -> result[n] = trim(result[n]));
            return result;
        }
    }

    class String
            implements Supplier<java.lang.String> {
        SplittableRandom r = new SplittableRandom(47);
        private int strlen = 7; // Default length

        public String() {
        }

        public String(int strLength) {
            strlen = strLength;
        }

        @Override
        public java.lang.String get() {
            return r.ints(strlen, 'a', 'z' + 1)
                    .collect(StringBuilder::new,
                            StringBuilder::appendCodePoint,
                            StringBuilder::append).toString();
        }

        public java.lang.String get(int n) {
            return get();
        }

        public java.lang.String[] array(int sz) {
            java.lang.String[] result =
                    new java.lang.String[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }
}
import java.util.Arrays;
import java.util.Collections;

import static com.example.test.ArrayShow.show;

public class StringSorting {
    public static void main(String[] args) {
        String[] sa = new Rand.String().array(20);
        show("Before sort", sa);
        Arrays.sort(sa);
        show("After sort", sa);
        Arrays.sort(sa, Collections.reverseOrder());
        show("Reverse sort", sa);
        Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER);
        show("Case-insensitive sort", sa);
    }
}

在这里插入图片描述

注意字符串排序算法中的输出。它是字典式的,所以它把所有以大写字母开头的单词放在前面,然后是所有以小写字母开头的单词。(电话簿通常是这样分类的。)无论大小写,要将单词组合在一起,请使用 String.CASE_INSENSITIVE_ORDER ,如对sort()的最后一次调用所示。

Java标准库中使用的排序算法被设计为最适合您正在排序的类型----原生类型的快速排序和对象的归并排序。

并行排序

如果排序性能是一个问题,那么可以使用 Java 8 parallelSort(),它为所有不可预见的情况(包括数组的排序区域或使用了比较器)提供了重载版本。为了查看相比于普通的sort(), parallelSort() 的优点,我们使用了用来验证代码时的 JMH

<dependency>
  <groupId>org.openjdk.jmh</groupId>
  <artifactId>jmh-core</artifactId>
  <version>1.29</version>
</dependency>

ParallelSort.java

import org.openjdk.jmh.annotations.*;

import java.util.Arrays;

@State(Scope.Thread)
public class ParallelSort {
    private long[] la;

    @Setup
    public void setup() {
        la = new Rand.Plong().array(100_000);
    }

    @Benchmark
    public void sort() {
        Arrays.sort(la);
    }

    @Benchmark
    public void parallelSort() {
        Arrays.parallelSort(la);
    }
}

parallelSort() 算法将大数组拆分成更小的数组,直到数组大小达到极限,然后使用普通的 Arrays .sort() 方法。然后合并结果。该算法需要不大于原始数组的额外工作空间。

您可能会看到不同的结果,但是在我的机器上,并行排序将速度提高了大约3倍。由于并行版本使用起来很简单,所以很容易考虑在任何地方使用它,而不是
Arrays.sort ()。当然,它可能不是那么简单—看看微基准测试。

binarySearch二分查找

一旦数组被排序,您就可以通过使用 Arrays.binarySearch() 来执行对特定项的快速搜索。但是,如果尝试在未排序的数组上使用 binarySearch(),结果是不可预测的。下面的示例使用 Rand.Pint 类来创建一个填充随机整形值的数组,然后调用 getAsInt() (因为 Rand.Pint 是一个 IntSupplier)来产生搜索值:

import java.util.Arrays;

import static com.example.test.ArrayShow.show;

public class ArraySearching {
    public static void main(String[] args) {
        Rand.Pint rand = new Rand.Pint();
        int[] a = new Rand.Pint().array(25);
        Arrays.sort(a);
        show("Sorted array", a);
        while (true) {
            int r = rand.getAsInt();
            int location = Arrays.binarySearch(a, r);
            if (location >= 0) {
                System.out.println("Location of " + r + " is " + location + ", a[" + location + "] is " + a[location]);
                break; // Out of while loop
            }
        }
    }
}

image.png

在while循环中,随机值作为搜索项生成,直到在数组中找到其中一个为止。

如果找到了搜索项,Arrays.binarySearch() 将生成一个大于或等于零的值。否则,它将产生一个负值,表示如果手动维护已排序的数组,则应该插入元素的位置。产生的值是 -(插入点) - 1 。插入点是大于键的第一个元素的索引,如果数组中的所有元素都小于指定的键,则是 a.size()

如果数组包含重复的元素,则无法保证找到其中的那些重复项。搜索算法不是为了支持重复的元素,而是为了容忍它们。如果需要没有重复元素的排序列表,可以使用 TreeSet (用于维持排序顺序)或 LinkedHashSet (用于维持插入顺序)。这些类自动为您处理所有的细节。只有在出现性能瓶颈的情况下,才应该使用手工维护的数组替换这些类中的一个。

如果使用比较器(原语数组不允许使用比较器进行排序)对对象数组进行排序,那么在执行 binarySearch() (使用重载版本的binarySearch())时必须包含相同的比较器。例如,可以修改 StringSorting.java 来执行搜索:

import java.util.Arrays;

import static com.example.test.ArrayShow.show;

public class AlphabeticSearch {
    public static void main(String[] args) {
        String[] sa = new Rand.String().array(30);
        Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER);
        show(sa);
        int index = Arrays.binarySearch(sa, sa[10], String.CASE_INSENSITIVE_ORDER);
        System.out.println("Index: " + index + "\n" + sa[index]);
    }
}

image.png

比较器必须作为第三个参数传递给重载的 binarySearch() 。在本例中,成功是有保证的,因为搜索项是从数组本身中选择的。

parallelPrefix并行前缀

没有“prefix()”方法,只有 parallelPrefix()。这类似于 Stream 类中的 reduce() 方法:它对前一个元素和当前元素执行一个操作,并将结果放入当前元素位置:

Count.java

package com.example.test;

import java.util.*;
import java.util.function.*;

import static com.example.test.ConvertTo.primitive;

public interface Count {
    class Boolean
            implements Supplier<java.lang.Boolean> {
        private boolean b = true;

        @Override
        public java.lang.Boolean get() {
            b = !b;
            return java.lang.Boolean.valueOf(b);
        }

        public java.lang.Boolean get(int n) {
            return get();
        }

        public java.lang.Boolean[] array(int sz) {
            java.lang.Boolean[] result =
                    new java.lang.Boolean[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pboolean {
        private boolean b = true;

        public boolean get() {
            b = !b;
            return b;
        }

        public boolean get(int n) {
            return get();
        }

        public boolean[] array(int sz) {
            return primitive(new Boolean().array(sz));
        }
    }

    class Byte
            implements Supplier<java.lang.Byte> {
        private byte b;

        @Override
        public java.lang.Byte get() {
            return b++;
        }

        public java.lang.Byte get(int n) {
            return get();
        }

        public java.lang.Byte[] array(int sz) {
            java.lang.Byte[] result =
                    new java.lang.Byte[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pbyte {
        private byte b;

        public byte get() {
            return b++;
        }

        public byte get(int n) {
            return get();
        }

        public byte[] array(int sz) {
            return primitive(new Byte().array(sz));
        }
    }

    char[] CHARS =
            "abcdefghijklmnopqrstuvwxyz".toCharArray();

    class Character
            implements Supplier<java.lang.Character> {
        private int i;

        @Override
        public java.lang.Character get() {
            i = (i + 1) % CHARS.length;
            return CHARS[i];
        }

        public java.lang.Character get(int n) {
            return get();
        }

        public java.lang.Character[] array(int sz) {
            java.lang.Character[] result =
                    new java.lang.Character[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pchar {
        private int i;

        public char get() {
            i = (i + 1) % CHARS.length;
            return CHARS[i];
        }

        public char get(int n) {
            return get();
        }

        public char[] array(int sz) {
            return primitive(new Character().array(sz));
        }
    }

    class Short
            implements Supplier<java.lang.Short> {
        short s;

        @Override
        public java.lang.Short get() {
            return s++;
        }

        public java.lang.Short get(int n) {
            return get();
        }

        public java.lang.Short[] array(int sz) {
            java.lang.Short[] result =
                    new java.lang.Short[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pshort {
        short s;

        public short get() {
            return s++;
        }

        public short get(int n) {
            return get();
        }

        public short[] array(int sz) {
            return primitive(new Short().array(sz));
        }
    }

    class Integer
            implements Supplier<java.lang.Integer> {
        int i;

        @Override
        public java.lang.Integer get() {
            return i++;
        }

        public java.lang.Integer get(int n) {
            return get();
        }

        public java.lang.Integer[] array(int sz) {
            java.lang.Integer[] result =
                    new java.lang.Integer[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pint implements IntSupplier {
        int i;

        public int get() {
            return i++;
        }

        public int get(int n) {
            return get();
        }

        @Override
        public int getAsInt() {
            return get();
        }

        public int[] array(int sz) {
            return primitive(new Integer().array(sz));
        }
    }

    class Long
            implements Supplier<java.lang.Long> {
        private long l;

        @Override
        public java.lang.Long get() {
            return l++;
        }

        public java.lang.Long get(int n) {
            return get();
        }

        public java.lang.Long[] array(int sz) {
            java.lang.Long[] result =
                    new java.lang.Long[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Plong implements LongSupplier {
        private long l;

        public long get() {
            return l++;
        }

        public long get(int n) {
            return get();
        }

        @Override
        public long getAsLong() {
            return get();
        }

        public long[] array(int sz) {
            return primitive(new Long().array(sz));
        }
    }

    class Float
            implements Supplier<java.lang.Float> {
        private int i;

        @Override
        public java.lang.Float get() {
            return java.lang.Float.valueOf(i++);
        }

        public java.lang.Float get(int n) {
            return get();
        }

        public java.lang.Float[] array(int sz) {
            java.lang.Float[] result =
                    new java.lang.Float[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pfloat {
        private int i;

        public float get() {
            return i++;
        }

        public float get(int n) {
            return get();
        }

        public float[] array(int sz) {
            return primitive(new Float().array(sz));
        }
    }

    class Double
            implements Supplier<java.lang.Double> {
        private int i;

        @Override
        public java.lang.Double get() {
            return java.lang.Double.valueOf(i++);
        }

        public java.lang.Double get(int n) {
            return get();
        }

        public java.lang.Double[] array(int sz) {
            java.lang.Double[] result =
                    new java.lang.Double[sz];
            Arrays.setAll(result, n -> get());
            return result;
        }
    }

    class Pdouble implements DoubleSupplier {
        private int i;

        public double get() {
            return i++;
        }

        public double get(int n) {
            return get();
        }

        @Override
        public double getAsDouble() {
            return get(0);
        }

        public double[] array(int sz) {
            return primitive(new Double().array(sz));
        }
    }
}

ParallelPrefix1.java

import java.util.Arrays;

import static com.example.test.ArrayShow.show;

public class ParallelPrefix1 {
    public static void main(String[] args) {
        int[] nums = new Count.Pint().array(10);
        show(nums);
        System.out.println(Arrays.stream(nums).reduce(Integer::sum).getAsInt());
        Arrays.parallelPrefix(nums, Integer::sum);
        show(nums);
        System.out.println(Arrays.stream(new Count.Pint().array(6)).reduce(Integer::sum).getAsInt());
    }
}

在这里插入图片描述

这里我们对数组应用Integer::sum。在位置0中,它将先前计算的值(因为没有先前的值)与原始数组位置0中的值组合在一起。在位置1中,它获取之前计算的值(它只是存储在位置0中),并将其与位置1中先前计算的值相结合。依次往复。

使用 Stream.reduce(),您只能得到最终结果,而使用 Arrays.parallelPrefix(),您还可以得到所有中间计算,以确保它们是有用的。注意,第二个 Stream.reduce() 计算的结果已经在 parallelPrefix() 计算的数组中。

使用字符串可能更清楚:

import java.util.Arrays;

import static com.example.test.ArrayShow.show;

public class ParallelPrefix2 {
    public static void main(String[] args) {
        String[] strings = new Rand.String(1).array(8);
        show(strings);
        Arrays.parallelPrefix(strings, (a, b) -> a + b);
        show(strings);
    }
}

在这里插入图片描述

如前所述,使用流进行初始化非常优雅,但是对于大型数组,这种方法可能会耗尽堆空间。使用 setAll() 执行初始化更节省内存:

import java.util.Arrays;

public class ParallelPrefix3 {
    static final int SIZE = 10_000_000;

    public static void main(String[] args) {
        long[] nums = new long[SIZE];
        Arrays.setAll(nums, n -> n);
        Arrays.parallelPrefix(nums, Long::sum);
        System.out.println("First 20: " + nums[19]);
        System.out.println("First 200: " + nums[199]);
        System.out.println("All: " + nums[nums.length - 1]);
    }
}

在这里插入图片描述

因为正确使用 parallelPrefix() 可能相当复杂,所以通常应该只在存在内存或速度问题(或两者都有)时使用。否则,Stream.reduce() 应该是您的首选。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/197002.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PLC:200smart

PLC&#xff1a;200smart 第十章、数据类型、数据存储1、数据类型1.1、有符号数1.2、有符号数 2、传送指令 第十一章、比较指令、整数、浮点数的运算1、比较指令1、运算指令1.1、浮点数运算1.2、整数运算 第十章、数据类型、数据存储 1、数据类型 数据类型分为两大类 无符号数…

Cream&Me 鲜奶油饼屋广州首店正式开业!

11月16日&#xff0c;Cream&#xff06;Me 鲜奶油饼屋在广州K11首店正式开业&#xff01; Cream&#xff06;Me鲜奶油饼屋与之前广州人气日式甜品品牌【KNOTKNOT珞珞】同属同一个团队打造&#xff0c;于2022年起筹备&#xff0c;首店于广州K11商场。C&#xff06;M以生日蛋糕日…

Vue3的项目创建到启动

Vue3的项目创建 检查node版本创建 npm init vuelatest 安装依赖 项目启动 启动成功

springcloud进销存管理系统源码

开发说明&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui 功能介绍&#xff1a; 后台管理&#xff1a; 统计分析&#xff1a;查看产品&#xff0c;采购&#xff0c;销售数量&#xff1b;统计近…

2023年【化工自动化控制仪表】考试资料及化工自动化控制仪表新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 化工自动化控制仪表考试资料参考答案及化工自动化控制仪表考试试题解析是安全生产模拟考试一点通题库老师及化工自动化控制仪表操作证已考过的学员汇总&#xff0c;相对有效帮助化工自动化控制仪表新版试题学员顺利通…

AutoSAR Classic Platform和Adaptive Platform 区别

概述 本文主要内容分为两章节。第一章节简要介绍了AUTOSAR的软件架构&#xff0c;设计理念以及方法论&#xff0c;对Classic Platform和Adaptive Platform做了简单的比较。第二章主要介绍了Adaptive Platform的特性。 第一章 AUTOSAR架构介绍 AUTOSAR(AUTomotive Open Syste…

解决苹果手机iphone手机强制重启

强制关机&#xff1a; 方法1.同时按住左侧的&#xff0c;- 键中的一个和右侧的电源键 方法2.点击桌面的悬浮键–设备–更多–重新启动

Jquery动画特效

1&#xff0c;Jquery提供的特效方法 2&#xff0c;实例代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

小程序如何进行一键修复

在使用小程序过程中&#xff0c;难免会遇到一些问题&#xff0c;比如程序崩溃、功能异常等等。这时&#xff0c;版本一键修复就显得尤为重要了。下面&#xff0c;我们就来介绍一下小程序如何进行版本一键修复。 一、什么是版本一键修复&#xff1f; 版本一键修复是指在小程序…

【图像分割】【深度学习】PFNet官方Pytorch代码-PFNet网络损失函数模块解析

【图像分割】【深度学习】PFNet官方Pytorch代码-PFNet网络损失函数模块解析 文章目录 【图像分割】【深度学习】PFNet官方Pytorch代码-PFNet网络损失函数模块解析前言PM定位模块损失函数FM聚焦模块损失函数总结 前言 在详细解析PFNet代码之前&#xff0c;首要任务是成功运行PF…

会声会影2024旗舰版系统配置要求及格式支持

会声会影2024旗舰版是一款广受欢迎的视频编辑软件&#xff0c;它的最新版本&#xff0c;会声会影2023&#xff0c;已经发布。在这篇文章中&#xff0c;我们将探讨会声会影2024旗舰版系统配置要求及格式支持 会声会影2024是一款专业的视频剪辑软件&#xff0c;能够帮助用户制作高…

vue+uniapp校园寻物失物招领平台 微信小程序1f6z5

系统中的核心用户是管理员&#xff0c;管理员登录后&#xff0c;通过管理员菜单来管理后台系统。主要功能有&#xff1a;首页、个人中心、用户管理、物品分类管理、物品信息管理、物品归还管理、留言板管理、系统管理等功能。管理员用例如图3-7所示。 对于本网上失物招领小程序…

unity3d地图、地面跟着NPC跑

清除烘焙后&#xff0c;再 将地图、地面的设置为非静态。只设置NPC的寻路路面为静态&#xff0c;再烘焙

03、K-means聚类实现步骤与基于K-means聚类的图像压缩(1)

03、K-means聚类实现步骤与基于K-means聚类的图像压缩&#xff08;1&#xff09; 03、K-means聚类实现步骤与基于K-means聚类的图像压缩&#xff08;1&#xff09; 03、K-means聚类实现步骤与基于K-means聚类的图像压缩&#xff08;2&#xff09; 开始学习机器学习啦&#xf…

电力智能化系统(智能电力综合监控系统)

电力智能化系统是一个综合性的系统&#xff0c;它利用物联网、云计算、大数据、人工智能等技术&#xff0c;依托电易云-智慧电力物联网&#xff0c;采用智能采集终端和物联网关&#xff0c;将电力设备、用电负荷、电力市场等各个环节有机地联系起来&#xff0c;实现了对电力配送…

一篇学会cron表达式

1、定义 Cron表达式是一种用于定义定时任务的格式化字符串。它被广泛用于Unix、Linux和类Unix系统中&#xff0c;用于在指定的时间执行预定的任务。Cron表达式由6个字段组成&#xff0c;每个字段通过空格分隔开。 在本文中&#xff0c;我们将学习如何理解和编写Cron表达式。 C…

Java高级技术(单元测试)

一&#xff0c;概括 二&#xff0c;junit 三&#xff0c;案例 &#xff08;1&#xff09;&#xff0c;实验类 package com.bilibili;public class Name {public static void main(String name) {if (name null){System.out.println("0");return;}System.out.print…

电子学会C/C++编程等级考试2022年06月(三级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:制作蛋糕 小A擅长制作香蕉蛋糕和巧克力蛋糕。制作一个香蕉蛋糕需要2个单位的香蕉,250个单位的面粉,75个单位的糖,100个单位的黄油。制作一个巧克力蛋糕需要75个单位的可可粉,200个单位的面粉,150个单位的糖,150个单位的黄…

MyBatis-Plus条件构造器

说明 Wrapper&#xff1a;条件构造抽象类&#xff0c;最顶端父类AbstractWrapper&#xff1a;用于查询条件封装&#xff0c;生成sql的where条件QueryWrapper&#xff1a;查询条件封装UpdateWrapper&#xff1a;更新条件封装AbstractLambdaWrapper&#xff1a;使用Lambda语法La…

基本数据结构二叉树(3)

目录 4.二叉树链式结构的操作 4.1 前置说明 4.2二叉树的遍历 4.2.1 前序、中序以及后序遍历 4.3 节点个数以及高度等 4.二叉树链式结构的操作 4.1 前置说明 由于博主对二叉树的结果掌握还不够深入&#xff0c;因此在讲解相关操作前将手动创建一颗简单的二叉树&#xff0c…