簡體   English   中英

使用 Java 從大型整數數組中刪除重復項

[英]Remove duplicates from a large integer array using Java

您知道使用 Java 從非常大的整數數組中刪除重復值的任何時間有效的方法嗎? 數組的大小取決於登錄的用戶,但總是會超過 1500000 個未排序的值,並且有一些重復。 每個整數都包含一個介於 100000 和 9999999 之間的數字。

我嘗試將其轉換為列表,但我服務器上的堆不允許有這么多數據(我的 ISP 已對其進行了限制)。 for 循環中的常規 for 循環需要超過 5 分鍾的時間來計算。

沒有重復的數組的大小是我將存儲在我的數據庫中的大小。

幫助將不勝感激!

你也許可以使用一些設置? 我不知道 Java 的 BitSet 效率如何。 但是 9999999 可能的值只需要 9999999 / 8 = 1250000 字節 = 剛好超過 1Mb。 在遍歷值數組時,將相應的位設置為 true。 然后,您可以遍歷該位集並在發現某個位設置為 true 時輸出相應的值。

1Mb 將適合 CPU 緩存,因此這可能非常有效,具體取決於位集實現。

這也有排序數據的副作用。

而且...這是一個 O(n) 算法,因為它需要對輸入數據進行一次傳遞,集合操作是 O(1)(對於像這樣的基於數組的集合),並且輸出傳遞也是 O( m) 其中 m 是唯一值的數量,根據定義,必須 <= n。

在開始向列表添加項目之前,我會創建一個哈希集,用於存儲列表中包含的所有值。 然后只需檢查哈希集是否不包含您要添加的值。

Set<Integer> set = new HashSet<Integer>();
Collections.addAll(set, array);

您只需要一個Integer[]數組而不是int[]

您可以先嘗試對數組進行排序:

int arr[] = yourarray;
Arrays.sort(arr);
// then iterate arr and remove duplicates
int[] a;
Arrays.sort(a);
int j = 0;
for (int i = 1; i < a.length; ++i) {
  if (a[i] != a[j]) {
    ++j;
    a[j] = a[i];
  }
}
// now store the elements from 0 to j (inclusive - i think)

真正絕望的人可以將數組寫入磁盤並分叉sort | uniq | wc -l <infile.txt sort | uniq | wc -l <infile.txt sort | uniq | wc -l <infile.txt並捕獲輸出。 如果內存仍然太緊或整數的域空間變大,則需要這樣做。 我不喜歡這個(他甚至在運行 unix!)但我的觀點是有很多方法可以完成任務。

另一個觀察結果是最小值為 100,000。 所以我們可以從最大值 9,999,999 中減去 100,000,減少域空間,從而節省一些內存。 也許 100k/8 位在事物的方案中是花生,但它本質上是免費的。

也許您可以對數據進行幾次傳遞? 例如,如果您對數據進行了 10 次傳遞,並將上述設置建議之一應用於較小的數據子集(例如,當 value mod pass# == 0 時)。 因此:

for (int i = 0 to 9) {
  set = new Set()
  for (each entry in the data set) {
    if (entry % i == 0) {
      set.add(entry)
    }
  }
  output set
}

通過這種方式,您將為內存權衡時間(增加傳遞次數以獲得更少的內存/更多的時間,反之亦然)。

也許一個使用原語而不是對象的散列集可以完成這項工作? 有免費的實現(以前沒有使用過,但也許它有效):

http://trove4j.sourceforge.net/

http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntHashSet.html

然后看起來像:

int[] newArray = new TIntHashSet(yourArray).toArray();

如果您確定整數具有合理的小值(例如總是大於零且小於 1000 或 10000),您可以嘗試這樣的技巧:

    final int MAX = 100; 
    int[] arrayWithRepeats = {99, 0, 10, 99, 0, 11, 99};

    //we are counting here integers with the same value
    int [] arrayOfValues = new int[MAX+1];
    int countOfUniqueIntegers = 0;
    for(int i : arrayWithRepeats) {
        if(arrayOfValues[i] == 0) {
            countOfUniqueIntegers++;
        }
        arrayOfValues[i]++;
    }

    // you can use arrayOfValues (smaller) or convert it
    // to table of unique values (more usable)

    int[] arrayOfUniqueValues = new int[countOfUniqueIntegers];
    int index = 0;
    for(int i = 0; i<arrayOfValues.length; i++) {
        if(arrayOfValues[i] != 0) {
            arrayOfUniqueValues[index] = i;
            index++;
        }
    }

    //and now arrayOfUniqueValues is even sorted
    System.out.println( Arrays.toString(arrayOfUniqueValues) );

輸出:[0, 10, 11, 99]

暫無
暫無

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

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