Jaka jest złożoność czasu metody String#substring()
w Javie?Złożoność czasowa podłoży Javy()
Odpowiedz
Nowa odpowiedź
Jak aktualizacji 6 w Java 7 za życia, zachowanie substring
zmieniony, aby utworzyć kopię - więc każdy String
odnosi się do char[]
która nie wspólny z żadnym innym obiektem, jak o ile wiem. W tym momencie substring()
stała się operacją O (n), gdzie n to liczby w podciągach.
Old odpowiedź: pre-Java 7
Undocumented - ale w praktyce O (1), jeśli nie ponoszą śmieci wymagane jest gromadzenie, itp
To po prostu buduje nowy obiekt nawiązujący do String
ten sam podstawowy char[]
, ale z różnymi wartościami przesunięcia i zliczenia. Koszt to czas potrzebny na przeprowadzenie walidacji i skonstruowanie pojedynczego nowego (stosunkowo małego) obiektu. To jest O (1), o ile rozsądnie jest mówić o złożoności operacji, które mogą zmieniać się w czasie w zależności od zbierania śmieci, pamięci podręcznych procesora itp. W szczególności nie zależy bezpośrednio od długości oryginalnego łańcucha lub podłańcucha .
+1 dla "nieudokumentowanego", co jest niefortunną słabością API. – Raedwald
To nie jest słabość.Jeśli zachowanie jest udokumentowane, a szczegóły implementacji nie, pozwala na szybsze implementacje w przyszłości. Zasadniczo Java często definiuje zachowanie, a implementacje decydują o tym, co jest najlepsze. Innymi słowy - nie powinieneś przejmować się tym, że to Java ;-) – peenut
Dobra racja, nawet jeśli nie wierzę, że kiedykolwiek uda się zrobić to szybciej niż O (1). – abahgat
O (1) ponieważ nie jest wykonywane kopiowanie oryginalnego ciągu, po prostu tworzy nowy obiekt opakowania z różnymi informacjami o przesunięciach.
Sędzia dla siebie z podążania, ale wady wydajności Java leżą gdzie indziej, nie tutaj w podciągu łańcucha. 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");
}
wyjściowa:
substring 32768 times Sum of lengths of splits = 1494414 Elapsed 2.446679 ms
Jeśli jest O (1), czy też nie, zależy. Jeśli po prostu odwołujesz się do tego samego ciągu znaków w pamięci, to wyobraź sobie, że masz długi łańcuch, robisz podciąg i przestajesz odwoływać się do długiego. Czy nie byłoby miło zwolnić pamięci na długi?
To była O (1) w starszych wersjach Javy - jak stwierdził Jon, po prostu stworzył nowy Ciąg z tym samym podstawowym znakiem [] oraz innym przesunięciem i długością.
to jednak faktycznie zmienił rozpoczął Java 7 aktualizacji 6.
char [] dzielenie został wyeliminowany, a przesunięcie i pola długości zostały usunięte. Funkcja substring() teraz kopiuje wszystkie znaki do nowego ciągu.
Ergo podciąg O (n) w Java 7 aktualizacją 6
+1 Tak jest w przypadku najnowszych wersji Sun Java i OpenJDK. GNU Classpath (i inne, jak zakładam) nadal używa starego paradygmatu. Niestety, wydaje się, że istnieje odrobina inercji intelektualnej w.r.t. to. Nadal widzę posty z 2013 r., W których zalecono różne podejścia oparte na założeniu, że podciągi używają wspólnej funkcji char, więc ... – thkala
Tak więc nowa wersja nie ma już złożoności O (1). Ciekawe, czy istnieje jakiś alternatywny sposób implementacji podciągów w O (1)? StringSubstring jest niezwykle przydatną metodą. –
Teraz złożoność liniowa. Jest to po naprawieniu problemu z przeciekiem pamięci dla podłańcucha.
Tak więc od wersji 1.7.0_06 Java należy pamiętać, że StringSubstring ma teraz złożoność liniową zamiast stałej.
Czy teraz jest gorzej (dla długich łańcuchów)? –
@ Myślę, że ponieważ jest to funkcja biblioteki, która jest często używana, słońce musiało to zoptymalizować :). więc O (1) – TimeToCodeTheRoad