2016-07-08 17 views
7

Mam ciasną pętlę, która wyszukuje coprimes. Lista primeFactors. Jej n-ty element zawiera posortowaną listę pierwotnego rozkładu n. Jestem sprawdzenie czy c i d są coprimes użyciu checkIfPrimesSkuteczny sposób sprawdzenia, czy dwie posortowane listy zawierają ten sam element Java.

boolean checkIfPrimes(int c, int d, List<List<Integer>> primeFactors) { 
    List<Integer> common = new ArrayList<>(primeFactors.get(d)); //slow 
    common.retainAll(primeFactors.get(c));   
    return (common.isEmpty()); 
} 

primeFactors.get(d).retainAll(primeFactors.get(c)) wygląda obiecująco, ale to zmienia mój wielokrotnego użytku primeFactors obiekt.

Tworzenie nowego obiektu odbywa się stosunkowo wolno. Czy istnieje sposób na przyspieszenie tego kroku? Czy mogę w jakiś sposób wykorzystać fakt, że listy są sortowane? Czy zamiast tego powinienem używać tablic?

+0

Jaką wersję Java? Jeśli masz 8+, masz sporo alternatyw związanych z wydajnością. – JoeG

+0

@JoeG Tak, to jest Java8. – sixtytrees

+0

Wygląda na to, że szukasz ['Collections.disjoint()'] (https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#disjoint (java.util. Kolekcja,% 20java.util.Collection)). – shmosel

Odpowiedz

1

Operacje ustawiania powinny być szybsze niż operacje na tablicach. tylko dla zabawy, za trudny to i porównać skuteczność przeciwko wykonywaniu strumieniowe:

final Set<Integer> commonSet; 
final Set<Integer> cSet = new HashSet<Integer>(); 
final Set<Integer> dSet = new HashSet<Integer>(); 

cSet.addAll(primeFactors.get(c)); 
dSet.addAll(primeFactors.get(d)); 

commonSet = dSet.retainAll(cSet); 

return (commonSet.isEmpty()); 

Również rozważyć użycie List<Set<Integer>> primeFactors zamiast List<List<Integer>> primeFactors ponieważ podejrzewam, że nie naprawdę mieć listę czynniki pierwsze ale w rzeczywistości mają szereg czynników pierwszorzędnych.

+0

Jeśli przechowujesz listę zestawów, nie utwórz nowe zestawy, po prostu użyj tych zestawów. – DwB

1

Zwykle można użyć tablicy boolowskiej. Gdzie indeksem tablicy jest liczba, a wartość wartości logicznej zwraca true, gdy jest ona pierwotna, w przeciwnym wypadku, false.

+0

Ta tablica zawiera dekompozycję pierwszych 10 milionów liczb. Tablica 10M x 3K ~ 30 G brzmi jak odcinek.realistycznie, potrzebowałbym 10M x 10M, jeśli nie chcę obliczać największych liczb pierwszych. – sixtytrees

+0

Okej, którego nie znałem. W końcu możesz użyć 'HashSet' dla liczb pierwszych? –

2

Można użyć numeru Collection z szybszym wyszukiwaniem - np. Set, jeśli potrzebujesz tylko czynników głównych bez powtórzeń lub Map, jeśli potrzebujesz również liczby każdego czynnika.

Zasadniczo chcesz wiedzieć, czy przecięcie dwóch zestawów jest puste. Oracle Set tutorial pokazuje sposób obliczania przecięcia (podobnego do tego, co już wspomniano, przy użyciu retainAll na kopii, ale w Ustawieniach operacja powinna być bardziej wydajna).

1

Można zrobić coś wzdłuż linii:

List<Integer> commonElements = 
     primeFactors.get(d).stream() 
          .filter(primeFactors.get(c)::contains) 
          .collect(Collectors.toList()); 

Po mierzyć tę skuteczność, można zastąpić „parallelStream()” dla „strumienia()” powyżej i zobacz, jakie korzyści czerpać.

+0

'parallelStream()' jest dla * naprawdę * długich strumieni lub dla * naprawdę * drogich zadań do obliczenia na każdym elemencie, nie dla listy czynników i filtrowania ich przez 'list :: constains' – leventov

2

Ponieważ Twoje listy są stosunkowo małe, a operacja ta jest wykonywana bardzo często, powinieneś unikać tworzenia nowych list lub zestawów, ponieważ może to prowadzić do znacznego ciśnienia GC.

Algorytm liniowego skanowania

public static boolean emptyIntersection(List<Integer> sortedA, List<Integer> sortedB) { 
    if (sortedA.isEmpty() || sortedB.isEmpty()) 
     return true; 
    int sizeA = sortedA.size(), sizeB = sortedB.size(); 
    int indexA = 0, indexB = 0; 
    int elementA = sortedA.get(indexA), elementB = sortedB.get(indexB); 
    while (true) { 
     if (elementA == elementB) { 
      return false; 
     } else if (elementA < elementB) { 
      indexA++; 
      if (indexA == sizeA) 
       return true; 
      elementA = sortedA.get(indexA); 
     } else { 
      // elementB < elementA 
      indexB++; 
      if (indexB == sizeB) 
       return true; 
      elementB = sortedB.get(indexB); 
     } 
    } 
} 

również rozważyć użycie list prymitywnych int s zamiast pudełkowych liczb całkowitych, np. sol. z biblioteki fastutil.

Powiązane problemy