পুনরাবৃত্তির পদ্ধতি কল কারণ হিসাবে কোটলিনে স্ট্যাকওভারফ্লোএরআর কিন্তু জাভাতে নয়


14

জাভা এবং কোটলিনে আমার প্রায় দুটি অভিন্ন কোড রয়েছে

জাভা:

public void reverseString(char[] s) {
    helper(s, 0, s.length - 1);
}

public void helper(char[] s, int left, int right) {
    if (left >= right) return;
    char tmp = s[left];
    s[left++] = s[right];
    s[right--] = tmp;
    helper(s, left, right);
}

Kotlin:

fun reverseString(s: CharArray): Unit {
    helper(0, s.lastIndex, s)
}

fun helper(i: Int, j: Int, s: CharArray) {
    if (i >= j) {
        return
    }
    val t = s[j]
    s[j] = s[i]
    s[i] = t
    helper(i + 1, j - 1, s)
}

জাভা কোডটি একটি বিশাল ইনপুট দিয়ে পরীক্ষায় উত্তীর্ণ হয় StackOverFlowErrorতবে কোটলিনে ফাংশনের tailrecআগে আমি কীওয়ার্ডটি যোগ না করা হলে কোটলিন কোড একটি কারণ helperঘটায়।

আমি জানতে চাই যে কেন এই ফাংশনটি জাভাতে এবং কোলিনের সাথে কাজ করে tailrecতবে কোটলিনে না ছাড়া tailrec?

PS: আমি জানি কি tailrecকরব


1
আমি যখন এগুলি পরীক্ষা করে দেখলাম যে জাভা সংস্করণটি অ্যারে আকারের জন্য প্রায় 29500 অবধি কাজ করবে তবে কোটলিন সংস্করণটি 18500 এর কাছাকাছি থামবে That's এটি একটি তাত্পর্যপূর্ণ পার্থক্য, তবে খুব বড় নয়। আপনার যদি বড় অ্যারেগুলির জন্য কাজ করার প্রয়োজন হয় তবে একমাত্র ভাল সমাধানটি ব্যবহার করা tailrecবা পুনরাবৃত্তি এড়ানো; উপলব্ধ স্ট্যাকের আকার রান, জেভিএম এবং সেট-আপগুলির মধ্যে এবং পদ্ধতি এবং তার প্যারামগুলির উপর নির্ভর করে পরিবর্তিত হয়। তবে যদি আপনি খাঁটি কৌতূহল জিজ্ঞাসা করে থাকেন (পুরোপুরি ভাল কারণ!) তবে আমি নিশ্চিত নই। আপনি সম্ভবত বাইকোড তাকান প্রয়োজন।
12 '12 এ গিডস

উত্তর:


7

আমি জানতে চাই কেন এই ফাংশন কাজ করে চান জাভা এবং kotlin সঙ্গে tailrecকিন্তু নেই kotlin ছাড়া tailrec?

সংক্ষিপ্ত উত্তর হ'ল আপনার কোটলিন পদ্ধতি JAVA এর চেয়ে "ভারী" । প্রতিটি কল এ এটি অন্য পদ্ধতিতে কল করে যা "উস্কানি দেয়" StackOverflowError। সুতরাং, নীচে আরও বিস্তারিত ব্যাখ্যা দেখুন।

জাভা বাইটকোড সমতুল্য reverseString()

আমি আপনার পদ্ধতিগুলির জন্য বাইট কোডটি কোটলিন এবং জাভাতে যথাযথভাবে পরীক্ষা করে দেখেছি :

JAVA এ কোটলিন পদ্ধতি বাইটকোড

...
public final void reverseString(@NotNull char[] s) {
    Intrinsics.checkParameterIsNotNull(s, "s");
    this.helper(0, ArraysKt.getLastIndex(s), s);
}

public final void helper(int i, int j, @NotNull char[] s) {
    Intrinsics.checkParameterIsNotNull(s, "s");
    if (i < j) {
        char t = s[j];
        s[j] = s[i];
        s[i] = t;
        this.helper(i + 1, j - 1, s);
    }
}
...

জাভা পদ্ধতিতে বাইকোড জাভা

...
public void reverseString(char[] s) {
    this.helper(s, 0, s.length - 1);
}

public void helper(char[] s, int left, int right) {
    if (left < right) {
        char temp = s[left];
        s[left++] = s[right];
        s[right--] = temp;
        this.helper(left, right, s);
    }
}
...

সুতরাং, এখানে 2 প্রধান পার্থক্য রয়েছে:

  1. Intrinsics.checkParameterIsNotNull(s, "s")প্রত্যেকের জন্য প্রার্থনা করা হয় helper()মধ্যে Kotlin সংস্করণ।
  2. জাভা পদ্ধতিতে বাম এবং ডান সূচকগুলি বর্ধিত হয়, কোটলিনে প্রতিটি পুনরাবৃত্তির জন্য নতুন সূচক তৈরি করা হয়।

সুতরাং, আসুন পরীক্ষা করা যাক কীভাবে Intrinsics.checkParameterIsNotNull(s, "s")একা আচরণকে প্রভাবিত করে।

উভয় বাস্তবায়ন পরীক্ষা করুন

আমি উভয় ক্ষেত্রেই একটি সহজ পরীক্ষা তৈরি করেছি:

@Test
public void testJavaImplementation() {
    char[] chars = new char[20000];
    new Example().reverseString(chars);
}

এবং

@Test
fun testKotlinImplementation() {
    val chars = CharArray(20000)
    Example().reverseString(chars)
}

জন্য জাভা পরীক্ষা সমস্যা ছাড়াই সফল কিছুদিনের জন্য Kotlin এটি একটি কারণে miserably ব্যর্থ হয়েছে StackOverflowError। তবে, আমি জাভা পদ্ধতিতে যুক্ত Intrinsics.checkParameterIsNotNull(s, "s")করার পরে এটিও ব্যর্থ হয়েছিল:

public void helper(char[] s, int left, int right) {
    Intrinsics.checkParameterIsNotNull(s, "s"); // add the same call here

    if (left >= right) return;
    char tmp = s[left];
    s[left] = s[right];
    s[right] = tmp;
    helper(s, left + 1, right - 1);
}

উপসংহার

আপনার কোটলিন পদ্ধতির একটি ছোট পুনরাবৃত্তির গভীরতা রয়েছে কারণ এটি Intrinsics.checkParameterIsNotNull(s, "s")প্রতিটি পদক্ষেপে আহ্বান জানায় এবং এটি তার জাভা সমমনা অংশের চেয়ে ভারী । আপনি যদি এই স্বয়ংক্রিয়ভাবে উত্পন্ন পদ্ধতিটি না চান তবে এখানে উত্তর হিসাবে সংকলনের সময় নাল চেকগুলি অক্ষম করতে পারেন

তবে, যেহেতু আপনি বুঝতে পেরেছেন কী উপকারটি tailrecনিয়ে আসে (আপনার পুনরাবৃত্ত কলকে পুনরাবৃত্ত একটিতে রূপান্তর করে) আপনার সেই ব্যবহারটি করা উচিত।


@ ব্যবহারকারী 207421 প্রতিটি পদ্ধতির অনুরোধের নিজস্ব স্ট্যাক ফ্রেম রয়েছে Intrinsics.checkParameterIsNotNull(...)। স্পষ্টতই, এই জাতীয় প্রতিটি স্ট্যাক ফ্রেমের জন্য একটি নির্দিষ্ট পরিমাণের মেমরির প্রয়োজন ( LocalVariableTableঅপারেণ্ড স্ট্যাক এবং এর জন্য) ..
আনাতোলি

0

কোটলিন হ'ল ক্ষুদ্র ক্ষুদ্র ক্ষুদ্র ক্ষুদ্র ক্ষুদ্র জনগণ (ইন্ট অবজেক্ট প্যারাম আইও ইন প্যারাম)। এখানে ফিট করে এমন টেল্রিক সমাধান ছাড়াও, আপনি জোর temp-ইন করে স্থানীয় ভেরিয়েবলটি মুছে ফেলতে পারেন :

fun helper(i: Int, j: Int, s: CharArray) {
    if (i >= j) {
        return
    }               // i: a          j: b
    s[j] ^= s[i]    //               j: a^b
    s[i] ^= s[j]    // i: a^a^b == b
    s[j] ^= s[i]    //               j: a^b^b == a
    helper(i + 1, j - 1, s)
}

এটি স্থানীয় ভেরিয়েবল অপসারণ করতে কাজ করে কিনা পুরোপুরি নিশ্চিত নয়।

জে বাদ দিতে পারে:

fun reverseString(s: CharArray): Unit {
    helper(0, s)
}

fun helper(i: Int, s: CharArray) {
    if (i >= s.lastIndex - i) {
        return
    }
    val t = s[s.lastIndex - i]
    s[s.lastIndex - i] = s[i]
    s[i] = t
    helper(i + 1, s)
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.