2017-02-16 3 views
2

Я студент, и я работал над следующей задачей: найти подстроку (иглу) в большей строке (стог сена) без использования метода substring и используя рекурсию. Рекурсия не мой конек, но я выработал следующее:Рекурсия ведет себя непредсказуемым образом с Java

public class Contains 
{ 
    public static void main(String[] args) 
    { 
     System.out.println(contains("Java programming", "ogr", false)); 
    } 

    public static boolean contains(String haystack, String needle, boolean doesContain) 
    { 
     if(haystack.length() < needle.length()) 
     { 
      return false; 
     } 
     else 
     { 
      for(int i = 0; i < needle.length(); i++) 
      { 
       if(haystack.charAt(i) != needle.charAt(i)) 
        if((i + 1) == needle.length()) 
         { 
          doesContain = false; 
          break; 
         } 
        else 
         break; 
       else 
        if((i + 1) == needle.length()) 
        { 
         doesContain = true; 
         break; 
        } 
        else 
         continue; 
      } 
      char[] haystackChar = haystack.toCharArray(); 
      char[] newCharArray = new char[(haystackChar.length - 1)]; 

      for(int j = 1; j < haystackChar.length; j++) 
      { 
       newCharArray[j - 1] = haystackChar[j]; 
      } 

      String newStr = new String(newCharArray); 

      if(doesContain == false) 
       contains(newStr, needle, doesContain); 
     } 
     return doesContain; 
    } 
} 

Я понимаю, что это не может быть лучшим или наиболее элегантным решением, но я в основном просто пытаюсь заставить его работать. Я запускаю его в отладчике Eclipse, и все работает так, как ожидалось, до вызова if(doesContain == false) во время вызова метода на contain, где doesContain имеет значение true во время итерации цикла for. Отладчик показывает значение doesContain, чтобы (правильно) быть истинным, и показывает, что он пропускает оператор if и выходит из блока else. Однако сразу после этого он перескакивает обратно в блок else и только вызывает рекурсивный вызов contain вместо того, чтобы возвращать doesContain. Затем он продолжает работать рекурсивно, а затем терпит неудачу и возвращает false, потому что теперь он просматривает остальную часть строки, где «игла» не находится.

Я знаю, что StackOverflow не является «домашней помощью», но я программирую для других целей, кроме школы, и я совершенно недоумеваю, почему он ведет себя таким образом. Кто-нибудь знает, почему он это делает? Я что-то упустил?

+1

О, мужик, мне жаль, что я не был девушкой, чтобы получить ответы на спам! В любом случае ваш (правда, плохо отформатированный) код работает нормально. Проблема в том, что вы отбрасываете результаты рекурсивных вызовов. Изменить 'содержит (newStr, needle, doesContain);' to 'return содержит (newStr, needle, doesContain);' и vòila! –

ответ

1

Я посмотрел через код и запустил его в затмить себя. Теория, которую вы захотите изучить, - это то, как складываются работы в рекурсии. Ваша программа находит правду, а затем выходит из стека, но к этому моменту она повторялась несколько раз. Он вернул значение true, но затем продолжил возвращать все ложные переменные, которые были сохранены до него.

Если у вас есть дополнительные вопросы, пожалуйста, дайте мне знать.

EDIT Если вы действительно заинтересованы в получении в продвинутую рекурсию я настоятельно рекомендую это видео: Java Recursion

Эй, мне не нужно идти так далеко, чтобы заставить его работать. Вы можете удалить hasContain в качестве параметра и установить его как статическую переменную экземпляра, и это сработало для меня.

public class Contains 
{ 

    private static boolean doesContain = false; 

    public static void main(String[] args) 
    { 
     System.out.println(contains("Java programming", "ogr")); 
    } 

    public static boolean contains(String haystack, String needle) 
    { 
     if(haystack.length() < needle.length()) 
     { 
      return false; 
     } 
     else 
     { 
      for(int i = 0; i < needle.length(); i++) 
      { 
       if(haystack.charAt(i) != needle.charAt(i)) 
        if((i + 1) == needle.length()) 
         { 
          doesContain = false; 
          break; 
         } 
        else 
         break; 
       else 
        if((i + 1) == needle.length()) 
        { 
         doesContain = true; 
         break; 
        } 
        else 
         continue; 
      } 
      char[] haystackChar = haystack.toCharArray(); 
      char[] newCharArray = new char[(haystackChar.length - 1)]; 

      for(int j = 1; j < haystackChar.length; j++) 
      { 
       newCharArray[j - 1] = haystackChar[j]; 
      } 

      String newStr = new String(newCharArray); 

      if(doesContain == false) 
       contains(newStr, needle); 
     } 
     return doesContain; 
    } 
} 

То, что вы были очень близок, но, передав его в качестве параметра вы хранили каждый раз, когда вы прошли через другую рекурсию. Таким образом вы возвращаете только свое окончательное значение.

+0

Когда вы говорите, что значение переменной равно null, какая переменная вы имеете в виду? Что-то, что уже существует в моем текущем коде или добавление новой переменной для оценки этого? Я несколько понимаю, что вы говорите о стеке, и я об этом не думал раньше. –

+0

Эй @ AbigailFox, извините за путаницу. То, о чем я говорил, было немного более продвинутым, чем вам нужно. Установив переменную экземпляра, вы можете сохранить одну копию файла doContain и не сохранять ее на каждом этапе рекурсии. Таким образом вы возвращаете только свое окончательное значение. –

+0

Спасибо! Оно работает! И также спасибо за ваше объяснение, рекурсивное мышление, вероятно, является навыком программирования, в котором я наихудший. Я даже не думал о том, как мой метод взаимодействует со стеклом и как обрабатывается логическое значение с помощью повторных вызовов методов. –

0

Чтобы найти needle в haystack так, как вы хотите, вам не нужно использовать рекурсию.

Просто удалите следующие строки кода из вашей функции, и он будет работать нормально:

 char[] haystackChar = haystack.toCharArray(); 
     char[] newCharArray = new char[(haystackChar.length - 1)]; 

     for(int j = 1; j < haystackChar.length; j++) 
     { 
      newCharArray[j - 1] = haystackChar[j]; 
     } 

     String newStr = new String(newCharArray); 

     if(doesContain == false) 
      contains(newStr, needle, doesContain); 
+0

Да, к сожалению, использование рекурсии - это требование для назначения. Лично я считаю, что рекурсия гораздо труднее понять, но я также понимаю, что я должен практиковать ее, чтобы иметь возможность использовать ее лучше. Спасибо за помощь, хотя! –

0

Я думаю, что вы вроде спутать себя с рекурсивной функцией. Одна из переменных, переданных рекурсивной функции, - doesContain, но функция должна вернуть, содержит ли строка ее! В строках

 if(doesContain == false) 
      contains(newStr, needle, doesContain); 

Вызов contains вернется, если подстрока содержит иглу. Вам нужно принять это значение и вернуть его обратно в стек вызовов.

Надеюсь, это имело смысл. Если это не так, я дам вам код, чтобы вы могли понять его из себя:

public static boolean contains(String haystack, String needle) 
{ 
    if(haystack.length() < needle.length()) 
    { 
     return false; 
    } 
    else 
    { 
     boolean doesContain=false; 
     for(int i = 0; i < needle.length(); i++) 
     { 
      if(haystack.charAt(i) != needle.charAt(i)) 
       if((i + 1) == needle.length()) 
        { 
         doesContain = false; 
         break; 
        } 
       else 
        break; 
      else 
       if((i + 1) == needle.length()) 
       { 
        doesContain = true; 
        break; 
       } 
       else 
        continue; 
     } 
     char[] haystackChar = haystack.toCharArray(); 
     char[] newCharArray = new char[(haystackChar.length - 1)]; 

     for(int j = 1; j < haystackChar.length; j++) 
     { 
      newCharArray[j - 1] = haystackChar[j]; 
     } 

     String newStr = new String(newCharArray); 

     if(doesContain == false) 
      return contains(newStr, needle); 
     else 
      return true; 
    } 
} 
+0

У меня действительно было такое, как раньше, добавление логического в вызов метода было одним из исправлений, которые я пытался решить. Я думал, что проблема могла заключаться в том, что я устанавливал 'doesContain' значение false в начале метода. На самом деле это не объясняло, почему он прыгал назад и не исправлял его, однако даже без него метод по-прежнему не возвращает правильное значение. –

+0

@AbigailFox wait, я тестировал его, и он работает. Он не прыгает назад, его выпрыгивает из функции, обратно к функции, которая называлась – AJC

+0

Что вы подразумеваете под этим? Как это делается? –

 Смежные вопросы

  • Нет связанных вопросов^_^