Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,如何仅在相同长度的位集设置为true的索引处对int[]进行排序_Java_Sorting_Java Stream - Fatal编程技术网

在Java中,如何仅在相同长度的位集设置为true的索引处对int[]进行排序

在Java中,如何仅在相同长度的位集设置为true的索引处对int[]进行排序,java,sorting,java-stream,Java,Sorting,Java Stream,虽然在Java中对连续子数组进行排序没有问题,但我没有找到任何关于如何仅在某些(非连续)索引处对数组进行排序的信息,这些索引由另一个数据结构指定,例如位集 具体来说,给定一个数组,如 int[] x = {5,1,8,6,7,0,2,3,9,4}; 以及指定要排序的位置的位集 BitSet pos = new BitSet(10); pos.set(0); pos.set(2); pos.set(5); pos.set(6); pos.set(9); // i.e. pos = {1,0,1,

虽然在Java中对连续子数组进行排序没有问题,但我没有找到任何关于如何仅在某些(非连续)索引处对数组进行排序的信息,这些索引由另一个数据结构指定,例如
位集

具体来说,给定一个数组,如

int[] x = {5,1,8,6,7,0,2,3,9,4};
以及指定要排序的位置的位集

BitSet pos = new BitSet(10);
pos.set(0);
pos.set(2);
pos.set(5);
pos.set(6);
pos.set(9); // i.e. pos = {1,0,1,0,0,1,1,0,0,1}
我只想在掩码
pos
1
的位置内联排序
x
,而忽略其余索引,即

SortOnIndices(x,pos);
应该导致

x = {0,1,2,6,7,4,5,3,9,8}
是否有任何有效的方法可以在不实施自定义排序解决方案的情况下对此进行归档?这可以通过Java8流实现吗


编辑:更正了示例中对位集的使用。

首先,
BitSet.valueOf(long[])
无法按您尝试的方式使用它。
long[]
数组的每个元素表示64位,而不是单个位。事实上,将
1,0,1,0,0,1,1,0,0,1
表示转换为
位集是第一个挑战:

BitSet pos = BitSet.valueOf(new long[] { Integer.reverse(0b1010011001)>>>22 });
然后,我们有一个问题,Java API的每个可定制排序实现都与对象一起工作,这将需要装箱并将源代码表示为数组或
列表
。为基元类型提供的方法都固定为自然顺序

试图创建一个位置列表或类似的列表,该列表映射到源数组时,在查找由位集引起的正确数组位置时,会受到非随机访问的影响。但是,
List.sort的
default
实现通过将列表内容复制到数组中来绕过这一点。这甚至适用于所有的
Stream
方法,这些方法使操作看起来流畅,但在幕后创建中间数组(并且还仅支持用于装箱值的自定义
Comparator

因此,当您想要避免额外的内存分配时,任何内置的排序功能都不会有帮助。最简单、有效和节省内存的方法是

BitSet ordered = new BitSet();
pos.stream().forEach(ix -> ordered.set(x[ix]));
PrimitiveIterator.OfInt it = ordered.stream().iterator();
pos.stream().forEachOrdered(ix -> x[ix]=it.next());
assert !it.hasNext();
但这仅在源数组不包含负数或重复数(如示例数据集中所示)时有效

解除这些限制需要更多的努力和更多的记忆:

IntSummaryStatistics stats = pos.stream().map(ix -> x[ix]).summaryStatistics();
int min = stats.getMin(), max = stats.getMax();
int[] counts = new int[max-min+1];
pos.stream().forEach(ix -> counts[x[ix]-min]++);
PrimitiveIterator.OfInt it
  = IntStream.rangeClosed(min, max)
             .flatMap(val -> IntStream.range(0, counts[val-min]).map(ix -> val))
             .iterator();
pos.stream().forEachOrdered(ix -> x[ix]=it.next());
assert !it.hasNext();
计数排序的这种变体仍然是O(n),但其内存消耗取决于要排序的数字集合中最小和最大数字之间的差异。但这是您能得到的最好结果,除非您想实现自己的快速排序或类似功能。或者,如果最小值和最大值之间的差异太大,您可以求助于让JRE提供的算法对副本进行排序:

int[] tmp = pos.stream().map(p -> x[p]).toArray();
Arrays.sort(tmp);
PrimitiveIterator.OfInt it = Arrays.stream(tmp).iterator();
pos.stream().forEachOrdered(ix -> x[ix]=it.next());
assert !it.hasNext();
您甚至可以使用第二个变量的统计信息来使用需要更少内存的变量

PrimitiveIterator.OfInt it;
IntSummaryStatistics stats = pos.stream().map(ix -> x[ix]).summaryStatistics();
int min = stats.getMin(), max = stats.getMax();
if(max-min < stats.getCount()) {
    int[] counts = new int[max-min+1];
    pos.stream().forEach(ix -> counts[x[ix]-min]++);
    it = IntStream.rangeClosed(min, max)
                  .flatMap(val -> IntStream.range(0, counts[val-min]).map(ix -> val))
                  .iterator();
}
else {
    int[] tmp = pos.stream().map(p -> x[p]).toArray();
    Arrays.sort(tmp);
    it = Arrays.stream(tmp).iterator();
}
pos.stream().forEachOrdered(ix -> x[ix]=it.next());
assert !it.hasNext();
PrimitiveIterator.ofit;
IntSummaryStatistics=pos.stream().map(ix->x[ix]).summaryStatistics();
int min=stats.getMin(),max=stats.getMax();
if(max-mincounts[x[ix]-min]++);
it=IntStream.rangeClosed(最小值、最大值)
.flatMap(val->IntStream.range(0,计数[val min]).map(ix->val))
.iterator();
}
否则{
int[]tmp=pos.stream().map(p->x[p]).toArray();
数组排序(tmp);
it=Arrays.stream(tmp.iterator();
}
pos.stream().forEachOrdered(ix->x[ix]=it.next());
断言!it.hasNext();

只将所需元素复制到一个新数组,对该数组进行排序,然后将它们复制回来,怎么样?@RomanPuchkovskiy这将是一个简单的解决方案,是的。我正在尝试最小化我的特定应用程序的内存占用,因为这些列表可能会变得相当大。这是一个多么好的第一个问题!真遗憾,你在这里没有得到应有的选票。我唯一想到的是一个虚拟的“就地”气泡排序,但这可能是非常愚蠢的。我保证会仔细考虑这个
位集。valueOf(long[])
的工作方式与您使用它的方式不同。我的错。我采纳这个问题是为了反映比特集的正确用法。感谢您提供了这个非常详细的答案。在使用JavaAPI时,我不知道幕后的复制机制。