2011-01-13 17 views

Antwort

90

Neue Antwort

Ab Update 6 in Java 7 Lebzeiten, das Verhalten von substring geändert, um eine Kopie zu erstellen - so dass jeder String auf eine char[] bezieht, die nicht geteilt mit einem anderen Objekt ist, wie soweit ich weiß. An diesem Punkt wurde substring() zu einer O (n) -Operation, wobei n die Zahlen in der Teilkette ist.

Alte Antwort: pre-Java 7

Undocumented - aber in der Praxis O (1), wenn Sie übernehmen keine Garbage Collection erforderlich ist, usw.

Es baut einfach ein neues String Objekt mit Bezug auf das gleiche zugrundeliegende char[] aber mit unterschiedlichen Offset- und Zählwerten. Die Kosten sind also die Zeit, die benötigt wird, um eine Validierung durchzuführen und ein einzelnes neues (relativ kleines) Objekt zu konstruieren. Das ist O (1), soweit es sinnvoll ist, über die Komplexität von Operationen zu sprechen, die sich aufgrund von Garbage-Collection, CPU-Caches usw. zeitlich ändern können. Insbesondere hängt sie nicht direkt von der Länge der ursprünglichen oder Teilzeichenfolge ab .

+10

+1 für "undokumentiert", was eine unglückliche Schwäche der API ist. – Raedwald

+9

Es ist keine Schwäche.Wenn das Verhalten dokumentiert ist und die Implementierungsdetails nicht vorhanden sind, ermöglicht dies schnellere Implementierungen in der Zukunft. Im Allgemeinen definiert Java häufig das Verhalten und lässt Implementierungen entscheiden, was am besten ist. Mit anderen Worten - Sie sollten sich nicht kümmern, schließlich ist es Java ;-) – peenut

+2

Guter Punkt Peenut, auch wenn ich kaum glaube, dass sie es jemals schaffen werden, diesen einen schneller zu machen als O (1). – abahgat

2

O (1) Da kein Kopieren der ursprünglichen Zeichenfolge durchgeführt wird, wird nur ein neues Wrapper-Objekt mit unterschiedlichen Offset-Informationen erstellt.

1

Beurteilen Sie selbst von folgenden, aber Java Leistungseinbußen liegen woanders, nicht hier in Teilstring einer Zeichenfolge. Code:

public static void main(String[] args) throws IOException { 

     String longStr = "asjf97zcv.1jm2497z20`1829182oqiwure92874nvcxz,nvz.,xo" + 
       "aihf[oiefjkas';./.,z][p\\°°°°°°°°?!(*#&(@*&#!)^(*&(*&)(*&" + 
       "fasdznmcxzvvcxz,vc,mvczvcz,mvcz,mcvcxvc,mvcxcvcxvcxvcxvcx"; 
     int[] indices = new int[32 * 1024]; 
     int[] lengths = new int[indices.length]; 
     Random r = new Random(); 
     final int minLength = 6; 
     for (int i = 0; i < indices.length; ++i) 
     { 
      indices[i] = r.nextInt(longStr.length() - minLength); 
      lengths[i] = minLength + r.nextInt(longStr.length() - indices[i] - minLength); 
     } 

     long start = System.nanoTime(); 

     int avoidOptimization = 0; 
     for (int i = 0; i < indices.length; ++i) 
      //avoidOptimization += lengths[i]; //tested - this was cheap 
      avoidOptimization += longStr.substring(indices[i], 
        indices[i] + lengths[i]).length(); 

     long end = System.nanoTime(); 
     System.out.println("substring " + indices.length + " times"); 
     System.out.println("Sum of lengths of splits = " + avoidOptimization); 
     System.out.println("Elapsed " + (end - start)/1.0e6 + " ms"); 
    } 

Ausgang:

substring 32768 times 
Sum of lengths of splits = 1494414 
Elapsed 2.446679 ms

Wenn es O (1) ist oder nicht, hängt davon ab. Wenn Sie nur den gleichen String im Speicher referenzieren, dann stellen Sie sich sehr long String vor, machen Sie Teilstring und stoppen Sie den Verweis auf lange. Wäre es nicht schön, die Erinnerung für lange Zeit freizugeben?

26

Es war O (1) in älteren Versionen von Java - wie Jon sagte, es hat nur einen neuen String mit dem gleichen zugrunde liegenden char [], und einen anderen Offset und Länge.

Dies hat jedoch tatsächlich begonnen änderte sich mit Java 7 Update 6.

Die char [] teilte eliminiert und die Offset- und Längenfelder wurden entfernt. substring() kopiert jetzt nur alle Zeichen in einen neuen String.

Ergo ist Teilzeichenfolge O (n) in Java 7 Update 6

+0

+1 Dies ist in den letzten Versionen von Sun Java und OpenJDK der Fall. GNU Classpath (und andere, nehme ich an) benutzen immer noch das alte Paradigma. Leider scheint es ein wenig intellektuelle Trägheit zu geben. Dies. Ich sehe immer noch Beiträge im Jahr 2013, die verschiedene Ansätze empfehlen, basierend auf der Annahme, dass Teilstrings ein gemeinsames 'char []' verwenden ... – thkala

+5

Eine neue Version hat also keine O (1) -Komplexität mehr. Neugierig zu wissen, gibt es eine alternative Möglichkeit, Teilkette in O (1) zu implementieren? Stringstring ist eine äußerst nützliche Methode. –

4

Es ist jetzt lineare Komplexität. Dies ist nach dem Beheben eines Speicherverlustproblems für Teilzeichenfolge.

So von Java 1.7.0_06 erinnern, dass Stringstring jetzt eine lineare Komplexität anstelle einer konstanten Komplexität hat.

+0

So ist es jetzt schlechter (für lange Saiten)? –