对数组进行排序并保留索引

时间:2016-12-13 02:26:34

标签: java arrays sorting indexof

使用Arrays.sort( array );是一种非常简单的数组排序方法。但有一个问题。对于每个未排序的数组,有一个索引引用某些其他数据结构中的对象。在对数组进行排序时(使用上面的代码或任何其他类似方法),将更改每个值的索引。是否有解决方案来为每个值分配索引?

修改

使用HashMap<Key, Value>没有用,因为数组中有很多相同的值。

2 个答案:

答案 0 :(得分:1)

并行对两个数据结构进行排序。

或者使引用索引(引用其他数据结构)成为每个元素的内部字段,以便每个元素保持相同的&#34;引用索引&#34;即使通过排序改变了元素的顺序。

或者更好的是,只需为每个元素提供一个内部字段,该字段只是另一个数据结构中元素的直接引用变量。 (除非您出于某种原因需要原始索引,而不仅仅是对相关对象/值的引用)

例如:this SO Q&A

答案 1 :(得分:0)

首先,有两个并行数组,其中包含相应索引中的元素,这表明您可能希望将数据结构更改为包含两个字段的容器对象的单个数组。然后,此容器对象将实现Comparable接口。

但是,坚持你所说的,一种方法可能是:

/**
 * Sorts parallel arrays in-place.  Sorted by the first array and updating
 * all other arrays to match.
 * Uses the natural sorting of the objects.
 * All arrays must be the same length.
 *
 * @param  keys         the values used to sort, may be duplicate
 *
 * @param  otherArrays  the arrays to have reordered to match the sorting of
 *                      the keys array.
 *
 * @exception  IllegalArgumentException  if any of otherArrays have a length
 *                      different that the keys array.
 */
public static <E extends Comparable<? super E>> void sortParallelArrays(
    E[] keys,
    Object[] ... otherArrays
) {
    int numKeys = keys.length;
    int numOtherArrays = otherArrays.length;
    for(Object[] otherArray : otherArrays) {
        if(otherArray.length != numKeys) {
            throw new IllegalArgumentException("Mismatched array lengths");
        }
    }
    // A list of all indexes per key
    // This also does the sorting within the TreeMap using natural ordering
    SortedMap<E, List<Integer>> originalIndexesByKey = new TreeMap<E, List<Integer>>();

    // Populate the map
    for(int i = 0; i < numKeys; i++) {
        E key = keys[i];
        List<Integer> originalIndexes = originalIndexesByKey.get(key);
        if(originalIndexes == null) {
            // Optimization for the non-duplicate keys
            originalIndexesByKey.put(key, Collections.singletonList(i));
        } else {
            if(originalIndexes.size() == 1) {
                // Upgrade to ArrayList now that know have duplicate keys
                originalIndexes = new ArrayList<Integer>(originalIndexes);
                originalIndexesByKey.put(key, originalIndexes);
            }
            originalIndexes.add(i);
        }
    }

    // Store back to keys and sort other arrays in a single traversal
    Object[][] sortedOtherArrays = new Object[numOtherArrays][numKeys];
    int pos = 0;
    for(Map.Entry<E, List<Integer>> entry : originalIndexesByKey.entrySet()) {
        E key = entry.getKey();
        for(int index : entry.getValue()) {
            keys[pos] = key;
            for(int ooIndex = 0; ooIndex < numOtherArrays; ooIndex++) {
                sortedOtherArrays[ooIndex][pos] = otherArrays[ooIndex][index];
            }
            pos++;
        }
    }
    assert pos == numKeys : "Arrays should be full";

    // Copy back to original arrays for in-place sort
    for(int ooIndex = 0; ooIndex < numOtherArrays; ooIndex++) {
        System.arraycopy(
            sortedOtherArrays[ooIndex], 0,
            otherArrays[ooIndex], 0,
            numKeys);
    }
}

这不是最节省内存的策略,但代码不多。

时间复杂度并不太糟糕。看起来像O((M+1)*N*log(N)),其中M是otherArrays的数量,N是键的数量。至少没有疯狂的最坏情况问题。