जावा के विकल्प की समय जटिलता ()


जवाबों:


137

नया जवाब

जावा 7 के जीवनकाल में अपडेट 6 के रूप में, substringप्रतिलिपि बनाने के लिए बदले जाने का व्यवहार - इसलिए प्रत्येक को Stringसंदर्भित किया जाता है char[]जिसे किसी अन्य वस्तु के साथ साझा नहीं किया जाता है, जहां तक ​​मैं जागरूक हूं। तो उस बिंदु पर, substring()एक ओ (एन) ऑपरेशन बन गया जहां एन सबस्ट्रिंग में संख्याएं हैं।

पुराना उत्तर: प्री-जावा Java

अनिर्धारित - लेकिन अभ्यास में ओ (1) यदि आप मानते हैं कि कोई कचरा संग्रह की आवश्यकता नहीं है, आदि।

यह एक Stringही अंतर्निहित के char[]साथ एक नई वस्तु बनाता है, लेकिन अलग-अलग ऑफसेट और गणना मूल्यों के साथ। तो लागत सत्यापन करने और एक नई (यथोचित छोटी) वस्तु के निर्माण में लगने वाला समय है। यह ओ (1) है जहाँ तक संचालन की जटिलता के बारे में बात करना समझदारी है जो कचरा संग्रहण, सीपीयू कैश इत्यादि के आधार पर अलग-अलग हो सकता है। विशेष रूप से, यह सीधे मूल स्ट्रिंग की लंबाई या विकल्प पर निर्भर नहीं करता है ।


14
"अनिर्दिष्ट" के लिए +1, जो एपीआई की एक दुर्भाग्यपूर्ण कमजोरी है।
राएडवल्ड

10
यह कमजोरी नहीं है। यदि व्यवहार प्रलेखित है, और कार्यान्वयन विवरण नहीं हैं, तो यह भविष्य में तेजी से कार्यान्वयन की अनुमति देता है। सामान्य तौर पर, जावा अक्सर व्यवहार को परिभाषित करता है और कार्यान्वयन को यह तय करने देता है कि सबसे अच्छा तरीका क्या है। दूसरे शब्दों में - आपको परवाह नहीं करनी चाहिए, आखिरकार, यह जावा ;-)
पीनट

2
अच्छा बिंदु पीनट, भले ही मुझे विश्वास है कि वे कभी भी ओ (1) की तुलना में इस तेजी से बनाने का प्रबंधन करेंगे।
अबाहगट १२'११

9
नहीं, ऐसा कुछ दस्तावेज होना चाहिए। एक डेवलपर को जागरूक होना चाहिए, बस अगर वह एक बड़े स्ट्रिंग का एक छोटा सा विकल्प लेने की योजना बना रहा है, तो यह अपेक्षा करता है कि बड़े स्ट्रिंग को कचरा एकत्र किया जाएगा जैसे कि यह .NET में होगा।
क्वर्टी

1
@ इवलायटोसकोव: नकल किए गए पात्रों की संख्या।
जॉन स्कीट

33

यह जावा के पुराने संस्करणों में O (1) था - जैसा कि जॉन ने कहा, उसने बस एक ही अंतर्निहित चार [], और एक अलग ऑफसेट और लंबाई के साथ एक नया स्ट्रिंग बनाया।

हालाँकि, यह वास्तव में जावा 7 अपडेट 6 से शुरू हुआ है।

चार [] साझाकरण को समाप्त कर दिया गया था, और ऑफसेट और लंबाई फ़ील्ड हटा दिए गए थे। सबस्ट्रिंग () अब बस सभी पात्रों को एक नए स्ट्रिंग में कॉपी करता है।

जावा 7 अपडेट 6 में Ergo, substring O (n) है


2
+1 हाल के सन जावा और ओपनजेडके संस्करणों में वास्तव में यही स्थिति है। जीएनयू क्लासपथ (और अन्य, मुझे लगता है) अभी भी पुराने प्रतिमान का उपयोग कर रहे हैं। दुर्भाग्य से यह बौद्धिक जड़ता का एक सा लगता है। मैं अब भी 2013 में पोस्ट देख रहा हूं कि इस धारणा के आधार पर विभिन्न दृष्टिकोणों की सिफारिश की गई है कि सबस्ट्रिंग एक साझा का उपयोग करते हैं char[]...
थकाला

10
इसलिए नए संस्करण में अब O (1) जटिलता नहीं है। यह जानने के लिए उत्सुक है कि क्या ओ (1) में प्रतिस्थापन को लागू करने का कोई वैकल्पिक तरीका है? String.substring एक अत्यंत उपयोगी विधि है।
यितोंग झोउ

8

यह अब रैखिक जटिलता है। यह प्रतिस्थापन के लिए स्मृति रिसाव समस्या को ठीक करने के बाद है।

तो Java 1.7.0_06 से याद रखें कि String.substring में अब स्थिरांक के बजाय एक रैखिक जटिलता है।


तो यह अब बदतर है (लंबे समय तक तार के लिए)?
पीटर मोर्टेंसन

@PeterMortensen हाँ।
डायमंड केसलर

3

जॉन के जवाब के लिए सबूत जोड़ना। मुझे एक ही संदेह था और यह जांचना चाहता था कि स्ट्रिंग की लंबाई का फंक्शनिंग फ़ंक्शन पर कोई प्रभाव पड़ता है या नहीं। निम्नलिखित पैरामीटर को जांचने के लिए कोड लिखा गया है, जो वास्तव में निर्भर करता है।

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;
        }
    }

}

जावा 8 में निष्पादन पर आउटपुट है:

 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

सबस्ट्रिंग फ़ंक्शन फ़ंक्शन स्ट्रिंग की लंबाई पर अनुरोध किए गए सबस्ट्रिंग की लंबाई पर निर्भर करता है।


1

O (1) क्योंकि मूल स्ट्रिंग की कोई भी नकल नहीं की जाती है, यह सिर्फ अलग-अलग ऑफसेट जानकारी के साथ एक नया आवरण ऑब्जेक्ट बनाता है।


1

निम्नलिखित में से खुद के लिए न्यायाधीश, लेकिन जावा के प्रदर्शन की कमियां कहीं और झूठ हैं, यहां स्ट्रिंग के विकल्प में नहीं। कोड:

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");
    }

आउटपुट:

32768 बार प्रतिस्थापित किया जा रहा है
विभाजन की लंबाई का योग = 1494414
बीता हुआ 2.446679 मि

यदि यह ओ (1) है या नहीं, निर्भर करता है। यदि आप स्मृति में केवल एक ही स्ट्रिंग का संदर्भ देते हैं, तो बहुत लंबी स्ट्रिंग की कल्पना करें , आप प्रतिस्थापन करते हैं और लंबे समय से संदर्भ को रोकते हैं। लंबे समय तक मेमोरी जारी करना अच्छा नहीं होगा?


0

जावा 1.7.0_06 से पहले : ओ (1)।

जावा 1.7.0_06 के बाद : O (n)। मेमोरी लीक की वजह से इसे बदल दिया गया था। खेतों के बाद offsetऔर countस्ट्रिंग से हटा दिए जाने के बाद , प्रतिस्थापन कार्यान्वयन ओ (एन) बन गया।

अधिक जानकारी के लिए, कृपया देखें: http://java-performance.info/changes-to-string-java-1-7-0_06/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.