二十一、数组(6)

news2024/11/16 10:21:01

本章概要

  • 数组排序
  • 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() 应该是您的首选。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

王者荣耀——Java

代码如下&#xff1a; sxt Background package sxt;import java.awt.*; //背景类 public class Background extends GameObject{public Background(GameFrame gameFrame) {super(gameFrame);}Image bg Toolkit.getDefaultToolkit().getImage("C:\\Users\\24465\\Desk…

Hibernate 脏检查和刷新缓存机制

刷新缓存: Session是Hibernate向应用程序提供的操作数据库的主要接口,它提供了基本的保存,更新,删除和加载java对象的方法,Session具有一个缓存,可以管理和追踪所有持久化对象,对象和数据库中的相关记录对应,在某些时间点,Session会根据缓存中对象的变化来执行相关SQL语句,将对…

【负载均衡】这些内容你需要知道下

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

【刷题宝典NO.4】

目录 公交站间的距离 生命游戏 公交站间的距离 https://leetcode.cn/problems/distance-between-bus-stops/ 环形公交路线上有 n 个站&#xff0c;按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离&#xff0c;distance[i] 表示编号为 i 的车站和编号为 …

Kotlin学习——流程控制,when,循环,range工具 kt里的equals if实现类似三元表达式的效果

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…

KVM虚拟机的NAT网络模式原理及过程展示

NAT的方式及原理 NAT方式是KVM安装后的默认方式。 它支持主机与虚拟机的互访&#xff0c;同时也支持虚拟机访问互联网&#xff0c;但不支持外界访问虚拟机。 default是宿主机安装虚拟机支持模块的时候自动安装的。 其中 virbr0是由宿主机虚拟机支持模块安装时产生的虚拟网络接…

Python编程技巧 – Lambda函数

Python编程技巧 – Lambda函数 Python Programming Skills – Lambda Functions By JacksonML 2023-11-25 在前文介绍过Python函数&#xff0c;一个函数用def关键字声明&#xff0c;不带或带有参数&#xff0c;并以冒号结束&#xff1b;函数块根据结果由解释器确定返回值动态…

【Linux】:信号的产生

信号 一.前台进程和后台进程1.前台进程2。后台进程3.总结 二.自定义信号动作接口三.信号的产生1.键盘组合键2.kill信号进程pid3.系统调用1.kill函数2.raise函数3.abort函数 四.异常五.软件条件六.通过终端按键产生信号 一.前台进程和后台进程 1.前台进程 一个简单的代码演示 …

【Spring集成MyBatis】MyBatis注解开发

文章目录 1. MyBatis的常用注解2. 基于注解的MyBatis增删改查增删改查完整代码加载映射关系测试代码 3. MyBatis的注解实现复杂映射开发一对一操作的实现一对一操作实现的第二种方式一对多操作的实现多对多操作实现 1. MyBatis的常用注解 2. 基于注解的MyBatis增删改查 使用注…

Leetcode—83.删除排序链表中的重复元素【简单】

2023每日刷题&#xff08;四十&#xff09; Leetcode—83.删除排序链表中的重复元素 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* deleteDuplicates(struct ListNode* head) {i…

张弛语言课,战争电影配音声音细致声音来复原战场

为战争片进行声音配音是一项挑战性的工作&#xff0c;它要求精确再现战场的紧张感和复杂情绪。配音人员和声音设计团队必须创造出真实的战争声景&#xff0c;从战斗的轰鸣声到士兵的呐喊&#xff0c;这些声音元素都需细致打造&#xff0c;以传递战争的惨烈、英勇和人性的复杂。…

工作中死循环害死人

背景&#xff1a;研发的一段代码&#xff0c;循环一直没有跳出&#xff0c;导致其他依赖逻辑有问题&#xff0c;生产事故导致9万左右数据不正常。 这里while&#xff08;true&#xff09;真的不要轻易用 &#xff0c;后来研发改动限制mysql的id切分步长&#xff0c;控制不会有数…

2017年2月16日 Go生态洞察:Go 1.8版本的革新

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

移动机器人路径规划(七)--- 基于MDP的路径规划MDP-Based Planning

目录 1 什么是MDP-Based Planning 2 worst-case analysis for nondeterministic model 3 Expected Cost Planning 4 Real Time Dynamic Programming&#xff08;RTDP&#xff09; 1 什么是MDP-Based Planning 之前我们从起点到终点存在很多可执行路径&#xff0c;我们可以…

可验证随机函数(VRF)

文章目录 一、背景以及场景共识发展第一代 POW “以力取胜”第二代 POS/DPOS “民主投票”第三代 VRF “运气抽签” 二、可验证随机函数&#xff08;VRF&#xff09;快速开始1. VRF是什么?2. MD5 hash函数和VRF&#xff08;Verifiable Random Function&#xff09;区别3. VRF-…

日历视图,轻松解决时间管理难题丨三叠云

日历组件 路径 仪表盘设计 >> 组件 功能简介 仪表盘新增「日历」组件。日历组件是以日历图的形式去呈现数据的一种方式&#xff0c;支持【列表模式】和【面板模式】。 【列表模式】&#xff1a; 通过日历方式筛选数据&#xff0c;数据将会以列表的方式呈现。 【面…

视频图片提取秘籍:从指定时长中提取想要的视频封面

在如今的内容丰富的互联网世界中&#xff0c;视频已经成为大家获取信息、娱乐和交流的重要方式之一。而视频的封面或图片&#xff0c;作为视频内容的“名片”&#xff0c;往往决定了观众是否愿意点击和进一步了解视频内容。视频图片提取&#xff0c;通常也被称为视频封面提取&a…

Python实现一箭穿心

文章目录 &#x1f384;效果&#x1f3f3;️‍&#x1f308;Turtle模块&#x1f339;代码&#x1f33a;代码讲解 &#x1f384;效果 &#x1f3f3;️‍&#x1f308;Turtle模块 Turtle是一个绘图工具&#xff0c;是Python标准库中的一个模块。它提供了一种简单而直观的方式来创…

【教学类-06-10】20231125(55格版)X-Y之间“乘法*题”(以1-9乘法口诀表为例)(0-9乘法口诀表 最大81)

图片展示 &#xff08;随机打乱排序&#xff09; 正序 背景需求&#xff1a; 2023年11月24日&#xff0c;准备了一些题目&#xff0c;分别给大4班孩子介绍“5以内加法、5以内减法、5以内加减混合”““10以内加法、10以内减法、10以内加减混合”“”20以内加减混合“七款学具…

Datax安装部署及读取MYSQL写入HDFS

一.DataX简介 1.DataX概述 DataX 是阿里巴巴开源的一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 源码地址&#xff1a;https://github.com/alibaba/Data…