2012-12-07 12 views
28

Ich frage mich, ob es eine effizientere Art und Weise von Vertauschen zweier Elemente in einem Array ist, als so etwas wie dies zu tun:Effektiver Austausch von Elementen eines Arrays in Java

String temp = arr[1]; 
arr[1] = arr[2]; 
arr[2] = temp; 

Nun, das ist natürlich nicht schlecht oder sogar falsch, aber ich muss sehr oft tauschen, also bin ich interessiert, ob es irgendwelche Libs gibt oder etwas, das einen effizienteren Weg bietet, dies zu tun?

+0

Bei String? Nein nicht wirklich. Wenn Sie es häufig tun müssen, können Sie auch einfach nur Ihre eigene Funktion rollen und dann ist es kein Problem – Grambot

+2

Wenn Sie mit List statt Array arbeiten können, können Sie Collections.swap (List, i, j) verwenden. –

+0

@Sergio Nakanishi: Interessanter Punkt, vielleicht kann ich zu Collections wechseln, aber ich bin mir nicht sicher, ob reine Array-Nutzung nicht schneller wäre? – Robin

Antwort

12

Nein. Sie könnten eine Funktion haben, die es an jedem Ort präziser macht, aber am Ende wäre die Arbeit die gleiche (plus der Overhead des Funktionsaufrufs, bis/außer HotSpot es inline verschoben   —, um damit zu helfen das, mach das functon static final).

+2

Nur für die Aufzeichnung, was ist der Vorteil bei der Verwendung von "statische final" statt nur "statische" oder gar keine? – Robin

+4

@Robin: 'static' sagt dem Compiler und der VM (denken Sie daran, HotSpot ist die VM, die eine Menge Laufzeitoptimierung durchführt), dass es sich nicht darum kümmern muss,' this' einzurichten, was die Inline-Funktion erleichtert . 'final' sagt, dass es in einer Unterklasse nicht überschrieben wird. Ich könnte mich leicht irren, in welchem ​​Maße sich HotSpot um eine von beiden kümmert, wirklich, ich bin nicht mit der neuesten Zauberei von HotSpot vertraut. :-) –

+2

Ich denke, dass Sie eine statische Methode nicht überschreiben können. –

5

Wenn Sie die Zeichenfolge austauschen möchten. Es ist bereits der effiziente Weg, dies zu tun.

Wenn Sie jedoch integer tauschen möchten, können Sie XOR verwenden zwei ganze Zahlen wie diese effizienter zu tauschen:

int a = 1; int b = 2; a ^= b; b ^= a; a ^= b; 
+2

Mit welchen Tests haben Sie das Benchmarking durchgeführt und welche Geschwindigkeitsverbesserungen wurden durchgeführt? – djechlin

+0

Siehe meinen Kommentar. – djechlin

+0

@djechlin mindestens, Sie brauchen keine temporäre Variable zu erstellen – bhuang3

20

Dies sollte es nahtlos machen:

public static final <T> void swap (T[] a, int i, int j) { 
    T t = a[i]; 
    a[i] = a[j]; 
    a[j] = t; 
} 

public static final <T> void swap (List<T> l, int i, int j) { 
    Collections.<T>swap(l, i, j); 
} 

private void test() { 
    String [] a = {"Hello", "Goodbye"}; 
    swap(a, 0, 1); 
    System.out.println("a:"+Arrays.toString(a)); 
    List<String> l = new ArrayList<String>(Arrays.asList(a)); 
    swap(l, 0, 1); 
    System.out.println("l:"+l); 
} 
+2

Das wäre meine Lösung gewesen, danke – Robin

+1

das funktioniert gut, danke. Beachten Sie, dass dies ein Array von Objekten erfordert. Wenn Sie diese komischen Fehler bei der Kompilierung vermeiden, stellen Sie sicher, dass Sie 'Integer [] array' anstelle von' int [] array' verwenden. – LostNomad311

1

Wenn Sie Tauschen Zahlen und wollen eine prägnante Möglichkeit, den Code zu schreiben, ohne eine separate Funktion zu erstellen oder einen verwirrenden XOR-Hack verwenden, finde ich, dass dies viel einfacher zu verstehen ist und es ist auch ein One-Liner.

Was ich von einigen primitiven Benchmarks gesehen habe, ist, dass der Leistungsunterschied im Grunde auch vernachlässigbar ist.

+0

aber arr [i] + arr [j] kann überlaufen –

+0

@ChaojunZhong das sollte kein Problem sein. Das neue '[i]' wird gut berechnet, wenn die andere Zahl subtrahiert wird. Versuchen Sie es in einer IDE – kmecpp

+0

Ja, Sie haben Recht. Das gleiche wie Sie sagen. –

0

Unglaublich spät zur Party (meine Entschuldigung), sondern eine allgemeinere Lösung, die hier nicht vorgesehen umgesetzt werden (wird mit Primitiven arbeiten und nicht-Primitiven gleichermaßen):

public static void swap(final Object array, final int i, final int j) { 
    final Object atI = Array.get(array, i); 
    Array.set(array, i, Array.get(array, j)); 
    Array.set(array, j, atI); 
} 

Sie kompilieren Zeit verlieren Sicherheit , aber es sollte den Trick machen.

Hinweis I: Sie erhalten eine NullPointerException, wenn der gegebene arraynull ist, eine IllegalArgumentException wenn die gegebene array ist nicht ein Array und ein ArrayIndexOutOfBoundsException wenn eine der beiden Indizes für die gegebene array nicht gültig sind.

Hinweis II: Mit separaten Methoden für diese für jeden Array-Typ (Object[] und alle primitiven Typen) wäre mehr performant (mit den anderen Ansätzen hier gegeben), da dies einige Boxen/Unboxing erfordert. Aber es wäre auch viel mehr Code zum Schreiben/Pflegen.

1

Versuchen Sie folgendes:

int lowIndex = 0; 
    int highIndex = elements.length-1; 

    while(lowIndex < highIndex) { 
     T lowVal = elements[lowIndex]; 
     T highVal = elements[highIndex]; 
     elements[lowIndex] = highVal; 
     elements[highIndex] = lowVal; 

     lowIndex += 1; 
     highIndex -=1; 
    } 
1

Verwenden Collections.swap und Arrays.asList:

Collections.swap(Arrays.asList(arr), i, j); 
Verwandte Themen