Wie groß ist die Komplexität von method retainAll bei Verwendung auf HashSets in Java?

8

Zum Beispiel im folgenden Code:

%Vor%     
Anirudh 15.07.2014, 09:44
quelle

2 Antworten

6

Nehmen wir einen Blick auf der Code . Die Methode retainAll wird von AbstractCollection geerbt und (zumindest in OpenJDK) sieht so aus:

%Vor%

Es gibt ein großes hier zu beachten, wir Schleife über this.iterator() und rufen c.contains . Die Zeitkomplexität ist also n ruft c.contains auf, wo n = this.size() und höchstens n auf it.remove() aufruft.

Wichtig ist, dass die Methode contains für andere Collection aufgerufen wird und die Komplexität daher von der Komplexität der anderen Collection contains abhängt.

Also, während:

%Vor%

wäre O(a.length) , da HashSet.contains und HashSet.remove beide O(1) (amortisiert) sind.

Wenn Sie

anrufen würden %Vor%

Dann würde dies aufgrund von O(n) contains auf Arrays.ArrayList zu O(a.length * b.length) werden - dh durch das Ausgeben von O(n) beim Kopieren des Arrays in HashSet wird der Aufruf von retainAll viel schneller ausgeführt.

Soweit Raumkomplexität erforderlich ist, wird von Iterator kein zusätzlicher Speicherplatz (über retainAll ) benötigt, aber Ihr Aufruf ist tatsächlich sehr teuer, da Sie zwei neue HashSet -Implementierungen zuweisen, die tatsächlich voll sind flügge HashMap .

Zwei weitere Dinge können angemerkt werden:

  1. Es gibt keinen Grund, HashSet von den Elementen in a zuzuteilen - eine billigere Sammlung, die auch O(1) remove von der Mitte hat, wie zB LinkedList , kann verwendet werden. (billiger im Speicher und auch bauen Zeit - eine Hash-Tabelle ist nicht gebaut)
  2. Ihre Änderungen gehen verloren, wenn Sie neue Sammlungsinstanzen erstellen und nur b.size() zurückgeben.
Boris the Spider 15.07.2014, 09:59
quelle
3

Die Implementierung befindet sich in der Klasse java.util.AbstractCollection . Die Art der Implementierung sieht folgendermaßen aus:

%Vor%

Also wird alles in Ihrer common Menge iteriert und geprüft, ob die Sammlung, die als Parameter übergeben wurde, dieses Element enthält.

In Ihrem Fall sind beide HashSet s, also wird es O (n) sein, da contains sollte O (1) amortisiert werden und Iterieren über Ihre common setzt ist O (n).

Eine Verbesserung, die Sie vornehmen können, besteht darin, einfach nicht a in ein neues HashSet zu kopieren, da es sowieso wiederholt wird, wenn Sie eine Liste behalten können.

    
Thomas Jungblut 15.07.2014 10:00
quelle

Tags und Links