二十一、数组(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);}@Overridepublic String toString() {String result = "[i = " + i + ", j = " + j + "]";if (count++ % 3 == 0) {result += "\n";}return result;}@Overridepublic 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> {@Overridepublic 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);@Overridepublic 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 Byteimplements Supplier<java.lang.Byte> {SplittableRandom r = new SplittableRandom(47);@Overridepublic 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 Characterimplements Supplier<java.lang.Character> {SplittableRandom r = new SplittableRandom(47);@Overridepublic 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 Shortimplements Supplier<java.lang.Short> {SplittableRandom r = new SplittableRandom(47);@Overridepublic 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 Integerimplements Supplier<java.lang.Integer> {SplittableRandom r = new SplittableRandom(47);@Overridepublic 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);@Overridepublic 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);@Overridepublic 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);@Overridepublic 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 Floatimplements Supplier<java.lang.Float> {SplittableRandom r = new SplittableRandom(47);@Overridepublic 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);@Overridepublic 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);@Overridepublic 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 Stringimplements Supplier<java.lang.String> {SplittableRandom r = new SplittableRandom(47);private int strlen = 7; // Default lengthpublic String() {}public String(int strLength) {strlen = strLength;}@Overridepublic 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;@Setuppublic void setup() {la = new Rand.Plong().array(100_000);}@Benchmarkpublic void sort() {Arrays.sort(la);}@Benchmarkpublic 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 Booleanimplements Supplier<java.lang.Boolean> {private boolean b = true;@Overridepublic 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 Byteimplements Supplier<java.lang.Byte> {private byte b;@Overridepublic 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 Characterimplements Supplier<java.lang.Character> {private int i;@Overridepublic 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 Shortimplements Supplier<java.lang.Short> {short s;@Overridepublic 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 Integerimplements Supplier<java.lang.Integer> {int i;@Overridepublic 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();}@Overridepublic int getAsInt() {return get();}public int[] array(int sz) {return primitive(new Integer().array(sz));}}class Longimplements Supplier<java.lang.Long> {private long l;@Overridepublic 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();}@Overridepublic long getAsLong() {return get();}public long[] array(int sz) {return primitive(new Long().array(sz));}}class Floatimplements Supplier<java.lang.Float> {private int i;@Overridepublic 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 Doubleimplements Supplier<java.lang.Double> {private int i;@Overridepublic 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();}@Overridepublic 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.mzph.cn/news/169674.shtml

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

相关文章

win11渗透武器库,囊括所有渗透工具

开箱即用&#xff0c;最全的武器库&#xff0c;且都是2023年11月最新版&#xff0c;后续自己还可以再添加&#xff0c;下载地址&#xff1a;https://download.csdn.net/download/weixin_59679023/88565739 服务连接 信息收集工具 端口扫描 代理抓包 漏洞扫描 指纹识别 webshel…

移动机器人路径规划(七)--- 基于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;我们可以…

Python实现一箭穿心

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

【C++】内存管理(new与delete)

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 前言 本篇文章我们一起来学习C的内存管理方式&…

最新yolov8环境搭建、推理训练一站式超详细教学

1、获取yolov8源码 访问yolov8_github官网&#xff0c;网络不稳定时可能需要加速器。yolov8源码地址 获取方式&#xff1a;直接下载或者git工具克隆 我使用git操作进行演示&#xff0c;复制github上的地址(需提前关闭加速器)。 git clone https://github.com/ultralytics/ul…

UI自动化(selenium+python)之元素定位的三种等待方式!

前言 在UI自动化过程中&#xff0c;常遇到元素未找到&#xff0c;代码报错的情况。这种情况下&#xff0c;需要用等待wait。 在selenium中可以用到三种等待方式即sleep,implicitly_wait,WebDriverWait 一、固定等待(sleep) 导入time模块&#xff0c;设定固定的等待时间 缺…

计数问题+约瑟夫问题(map)

目录 一、计数问题 二、约瑟夫问题 一、计数问题 #include<iostream> #include<map> using namespace std; int main() {int n,x;cin>>n>>x;map<int,int>m;for(int i1;i<n;i){if(i>1 && i<10){m[i];}else{int temp i;while (…

解决github无法访问的办法

方法/步骤 1.问题描述&#xff1a;能联网但不能访问github.com 2.找到hosts文件。地址&#xff1a;C:\Windows\System32\drivers\etc &#xff08;一般是在这的&#xff09; 3.不要直接在这修改hosts文件&#xff0c;需要将hosts文件复制粘贴到桌面&#xff08;或其它地方自…

【仿写实现move函数】

仿写实现move函数 一、值的类型 1.左值 描述&#xff1a;能够取地址的值成为左值 int a 10; const int b 15; int *pa &a; const int *pb &b;2.纯右值 描述&#xff1a;赤裸裸的字面值 eg(false , 3 , 12.23等) int a 13; int *p &a; //取a的地址 int …

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

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

leaflet对线设置渐变色

效果展示&#xff1a; 引用leaflet-polycolor组件 npm install leaflet-polycolor .vue文件中使用 import leafletPolycolor from leaflet-polycolor; leafletPolycolor(L); const latLngs [[37.03, 111.92], [37.53444, 111.98555], [36.88, 112.12], [37.53444, 112.24], […

MT6893_天玑 1200芯片规格参数介绍_datasheet规格书

天玑 1200(MT6893)是一款专为旗舰级全新5G芯片&#xff0c;它融合了先进的AI、相机和多媒体技术&#xff0c;为用户带来令人惊叹的体验。采用先进的6纳米制程设计&#xff0c;内置各种先进技术。该芯片采用旗舰级的八核CPU架构设计&#xff0c;支持16GB强大的四通道内存以及双通…

每日一练:“打家劫舍“(House Robber)问题 II

有想要了解打家劫舍初级问题的&#xff0c;可以点击下面链接查看&#xff01; 每日一练&#xff1a;“打家劫舍“&#xff08;House Robber&#xff09;问题 I 1. 问题 假设有房屋形成一个环形&#xff0c;即第一个房屋和最后一个房屋也相邻&#xff0c;每个房屋里都存放着一定…

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…

【Docker】Docker 仓库管理和Docker Dockerfile

作者简介&#xff1a; 辭七七&#xff0c;目前大二&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

MybatisPlus集成baomidou-dynamic,多数据源配置使用、MybatisPlus分页分组等操作示例

文章目录 pom配置示例代码 pom <dependencies><!--mybatisPlus集成SpringBoot起步依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version>&l…

【DP】mobiusp正在创作乐曲

输入样例1&#xff1a; 5 2 1 7 7 1 3 输出样例1&#xff1a; 2 输入样例2&#xff1a; 10 3 2 5 6 4 4 5 7 3 5 6 输出样例2&#xff1a; 1 #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; typede…

SpringCloud实用-OpenFeign整合okHttp

文章目录 前言正文一、OkHttpFeignConfiguration 的启用1.1 分析配置类1.2 得出结论&#xff0c;需要增加配置1.3 调试 二、OkHttpFeignLoadBalancerConfiguration 的启用2.1 分析配置类2.2 得出结论2.3 测试 附录附1&#xff1a;本系列文章链接附2&#xff1a;OkHttpClient 增…

10.打印楼梯图案和笑脸【2023.11.25】

1.问题描述 打印楼梯图案和笑脸 2.解决思路 3.代码实现 #include<stdio.h> int main(){printf("11\n");for(int i0;i<10;i){for(int j0;j<i;j){printf("FF"); }printf("\n");} return 0; }4.运行结果

《微信小程序开发从入门到实战》学习二十九

3.4 开发参与投票页面 3.4.4 使用label组件扩大单击区域 radio组件的单击区域很小&#xff0c;只有文字左侧的圆圈可以点击&#xff0c;实际使用者一般会期望点击文字也可以选中选项&#xff0c;用label组件包含radio组件&#xff0c;就可以实现点击文字也可以选项。 label组…