String#substring()
Java'da yöntemin zaman karmaşıklığı nedir ?
String#substring()
Java'da yöntemin zaman karmaşıklığı nedir ?
Yanıtlar:
Yeni cevap
Java 7'nin ömrü içinde güncelleme 6 itibariyle davranışı substring
değişti bir kopyasını oluşturmak için - her öylesine String
bir atıfta char[]
hangi değil başka bir nesne ile paylaşılan, bildiğim kadarıyla farkındayım olarak. Bu noktada, substring()
n'nin alt dizedeki sayılar olduğu bir O (n) işlemi oldu.
Eski cevap: Java 7 öncesi
Belgelenmemiş - ancak pratikte O (1) çöp toplamanın gerekli olmadığını varsayarsanız, vb.
Basitçe String
aynı temele atıfta bulunan char[]
ancak farklı ofset ve sayım değerlerine sahip yeni bir nesne oluşturur . Dolayısıyla maliyet, doğrulamayı gerçekleştirmek ve tek bir yeni (makul ölçüde küçük) nesne oluşturmak için geçen süredir. Çöp toplama, CPU önbellekleri vb. Temelinde zaman içinde değişebilen işlemlerin karmaşıklığından bahsetmek mantıklı olduğu ölçüde O (1) değeridir. Özellikle, doğrudan orijinal dizenin veya alt dizenin uzunluğuna bağlı değildir .
Java'nın eski sürümlerinde O (1) idi - Jon'un belirttiği gibi, aynı temel karakter [] ve farklı bir uzaklık ve uzunluk ile yeni bir String oluşturdu.
Ancak, bu aslında Java 7 güncelleme 6 ile başlayan değişti.
Char [] paylaşımı kaldırıldı ve ofset ve uzunluk alanları kaldırıldı. substring () artık tüm karakterleri yeni bir String'e kopyalar.
Ergo, Java 7 güncelleme 6'da alt dize O (n)
char[]
Artık doğrusal karmaşıklık. Bu, alt dizeyle ilgili bir bellek sızıntısı sorununu düzelttikten sonradır.
Yani Java 1.7.0_06'dan String.substring'in artık sabit bir karmaşıklık yerine doğrusal bir karmaşıklığa sahip olduğunu hatırlayın.
Jon'un cevabına kanıt eklemek. Aynı şüphem vardı ve dizge uzunluğunun alt dize işlevi üzerinde herhangi bir etkisi olup olmadığını kontrol etmek istedim. Hangi parametre alt dizesinin gerçekte bağlı olduğunu kontrol etmek için aşağıdaki kod yazılmıştır.
import org.apache.commons.lang.RandomStringUtils;
public class Dummy {
private static final String pool[] = new String[3];
private static int substringLength;
public static void main(String args[]) {
pool[0] = RandomStringUtils.random(2000);
pool[1] = RandomStringUtils.random(10000);
pool[2] = RandomStringUtils.random(100000);
test(10);
test(100);
test(1000);
}
public static void test(int val) {
substringLength = val;
StatsCopy statsCopy[] = new StatsCopy[3];
for (int j = 0; j < 3; j++) {
statsCopy[j] = new StatsCopy();
}
long latency[] = new long[3];
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 3; j++) {
latency[j] = latency(pool[j]);
statsCopy[j].send(latency[j]);
}
}
for (int i = 0; i < 3; i++) {
System.out.println(
" Avg: "
+ (int) statsCopy[i].getAvg()
+ "\t String length: "
+ pool[i].length()
+ "\tSubstring Length: "
+ substringLength);
}
System.out.println();
}
private static long latency(String a) {
long startTime = System.nanoTime();
a.substring(0, substringLength);
long endtime = System.nanoTime();
return endtime - startTime;
}
private static class StatsCopy {
private long count = 0;
private long min = Integer.MAX_VALUE;
private long max = 0;
private double avg = 0;
public void send(long latency) {
computeStats(latency);
count++;
}
private void computeStats(long latency) {
if (min > latency) min = latency;
if (max < latency) max = latency;
avg = ((float) count / (count + 1)) * avg + (float) latency / (count + 1);
}
public double getAvg() {
return avg;
}
public long getMin() {
return min;
}
public long getMax() {
return max;
}
public long getCount() {
return count;
}
}
}
Java 8'de yürütme çıktı:
Avg: 128 String length: 2000 Substring Length: 10
Avg: 127 String length: 10000 Substring Length: 10
Avg: 124 String length: 100000 Substring Length: 10
Avg: 172 String length: 2000 Substring Length: 100
Avg: 175 String length: 10000 Substring Length: 100
Avg: 177 String length: 100000 Substring Length: 100
Avg: 1199 String length: 2000 Substring Length: 1000
Avg: 1186 String length: 10000 Substring Length: 1000
Avg: 1339 String length: 100000 Substring Length: 1000
Alt dize işlevinin kanıtlanması, dizenin uzunluğuna değil, istenen alt dizenin uzunluğuna bağlıdır.
Kendinizi takip ederek yargılayın, ancak Java'nın performans dezavantajları başka bir yerde yatıyor, burada bir dizenin alt dizesinde değil. Kod:
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");
}
Çıktı:
32768 kez alt dize Bölme uzunluklarının toplamı = 1494414 Geçen 2,446679 ms
O (1) olup olmaması bağlıdır. Bellekte sadece aynı String'e başvurursanız, çok uzun String'i hayal edin , alt dize oluşturur ve uzun olanı referans vermeyi bırakırsınız. Uzun bir hatırayı serbest bırakmak güzel olmaz mıydı?
Java 1.7.0_06'dan önce : O (1).
Java 1.7.0_06'dan sonra : O (n). Bellek sızıntısı nedeniyle bu değiştirildi. Alanlardan sonra offset
ve count
String'den çıkarıldıktan sonra, alt dize uygulaması O (n) oldu.
Daha fazla ayrıntı için lütfen şu adrese bakın: http://java-performance.info/changes-to-string-java-1-7-0_06/