簡體   English   中英

排序后獲取未排序的雙精度數組的索引

[英]Getting the indices of an unsorted double array after sorting

這個問題來,因為這的同伴一個是認為最快的雙數組排序。

現在,我想獲取對應於未排序數組的前k索引。

我已經實現了這個版本,它(不幸)使用自動裝箱和HashMap ,如一些答案,包括這個建議一個

HashMap<Double, Integer> map = new HashMap<Double, Integer>();
for(int i = 0; i < numClusters; i++) {
    map.put(scores[i], i);
}
Arrays.sort(scores);
HashSet<Integer> topPossibleClusters = new HashSet<Integer>();
for(int i = 0; i < numClusters; i++) {
    topPossibleClusters.add(map.get(scores[numClusters - (i+1)]));
}

如您所見,這使用HashMap ,其鍵具有原始數組的Double值和原始數組的索引作為鍵的值。 因此,在對原始數組進行排序之后,我只是從map檢索它。

我也使用HashSet因為我有興趣使用.contains()方法確定此集合中是否包含int (我不知道這是否有區別,因為正如我在另一個問題中提到的那樣,我的數組很小-50個元素-)。 如果沒有什么區別,請指出。

我對價值本身不感興趣,僅對指數感興趣。

我的問題是,是否有更快的方法?

這種相互鏈接/互鎖的集合使自己容易碎,容易損壞,難以調試,無法維護的代碼。

而是創建一個對象:

class Data {
    double value;
    int originalIndex;
}

創建一個存儲原始值和索引的Data對象數組。

使用自定義比較器對它們進行排序,該比較器查看data.value並對降序進行排序。

現在,數組中最重要的X項就是所需的項,您可以根據需要查看valueoriginalIndex

正如Tim指出的那樣,鏈接多個集合很容易出錯。 我建議使用TreeMap因為這將允許一個獨立的解決方案。

假設您有double[] data ,首先將其復制到TreeMap

final TreeMap<Double, Integer> dataWithIndex = new TreeMap<>();
for(int i = 0; i < data.length; ++i) {
    dataWithIndex.put(data[i], i);
}

注意:您可以將dataWithIndex聲明為NavigableMap不太具體,但是它要長得多,並且實際上並沒有增加太多,因為JDK中只有一個實現。

這將在O(n lg n)時間內填充Map ,因為每個put均為O(lg n) -這與排序的復雜度相同。 實際上,它可能會稍微慢一些,但它會以相同的方式擴展

現在,假設您需要第k元素,首先需要找到第k個元素-這是O(k)

final Iterator<Double> keyIter = dataWithIndex.keySet().iterator();
double kthKey;
for (int i = 0; i < k; ++i) {
    kthKey = keyIter.next();
}

現在,您只需要獲取具有所有條目直到第k個條目的子映射:

final Map<Double, Integer> topK = dataWithIndex.headMap(kthKey, true);

如果只需要執行一次,那么使用Java 8可以執行以下操作:

List<Entry<Double, Integer>> topK = IntStream.range(0, data.length).
        mapToObj(i -> new SimpleEntry<>(data[i], i)).
        sorted(comparing(Entry::getKey)).
        limit(k).
        collect(toList());

IntStream ,使用IntStream獲取data索引,並將mapToObjdata[i] => iEntry (使用AbsractMap.SimpleEntry實現)。 現在使用Entry::getKey排序,並將Stream的大小限制為k個條目。 現在,只需將結果收集到List 這具有不破壞data陣列中重復項的優點。

這幾乎完全是Tim在他的答案中所建議的,但是使用了現有的JDK類。

該方法也是O(n lg n) 要注意的是,如果重用TreeMap方法,則O(n lg n)來構建Map而只有O(k)可以重用它。 如果要重復使用Java 8解決方案,則可以執行以下操作:

List<Entry<Double, Integer>> sorted = IntStream.range(0, data.length).
        mapToObj(i -> new SimpleEntry<>(data[i], i)).
        sorted(comparing(Entry::getKey)).
        collect(toList());

即不要將大小限制為k元素。 現在,要獲取前k元素,您只需要做:

List<Entry<Double, Integer>> subList = sorted.subList(0, k);

這樣做的魔力在於它是O(1)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM