Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Java: Merkkijonon kääntö rekursiolla

lrp [04.08.2012 20:20:16]

#

(Mod. siirsi rekursio-oppaan kommenteista.)

Törmäsin opettavaisen tuntuiseen esimerkkiin.

#include <iostream>

using namespace std;
void reverse(char *a);
int main(int argc, char *argv[])
{
    char str[] = "This is a test";
    reverse(str);
}
void reverse(char *a){
     if (*a)
        reverse(a+1);
     else
          return;
     cout<< *a;
}

Sitten kokeilin tehdä saman Javalla. Siitä tuli vähän monimutkaisempi, mutta lyhyt.

public class Ohjelma {

    public static void main(String[] args) {
        String str = "hello";
        System.out.println(reverse(str, 0));
    }
    public static String reverse (String instring, int indeksi){
        if (indeksi < instring.length()){
            return reverse(instring, indeksi+1)+instring.charAt(indeksi);
        }
        else return "";
    }
}

Saisko tämän Javalla jotenkin ytimekkäämmäksi? Onko toi kakkosparametri pakko olla?

Koitin hahmotella itselleni pinon toimintaa.

kutsu                      arvo                pinon purkautuessa
                           pinoon mennessä
6. kutsu palauttaa->       ""                  ""
5. kutsu palauttaa->       6. kutsu + o        ""o
4. kutsu palauttaa->       5. kutsu + l        ""ol
3. kutsu palauttaa->       4. kutsu + l        ""oll
2. kutsu palauttaa->       3. kutsu + e        ""olle
1. kutsu palauttaa->       2. kutsu + h        ""olleh
"" tarkoittaa, että mitään ei mene merkkijonoon.
str="hello";
str.length() == reverse(hello, 0).length()

fergusq [23.04.2013 19:26:49]

#

lrp kirjoitti:

Saisko tämän Javalla jotenkin ytimekkäämmäksi? Onko toi kakkosparametri pakko olla?

No ton java-ohjelman saa suoraan käännettyä C++:sta näin:

public static void reverse (String a){
    if (!a.isEmpty()){
        reverse(a.substring(1));
    }
    else return;

    System.out.print(a.charAt(0));
}

Ja niin että se palauttaa merkkijonon:

public static String reverse (String a){
    if (!a.isEmpty()){
        return reverse(a.substring(1))+a.charAt(0);
    }
    else return "";
}

Metabolix [24.04.2013 22:16:28]

#

Tyylivalitusta seuraa. Tuo alkuperäinen koodi on kyllä taas hieno esimerkki if-else-rakenteen epäselvästä käytöstä. Koodissa rekursiivinen kutsu ja merkin tulostus kuuluvat kiinteästi yhteen, joten ne olisi viisainta laittaa joko yhdessä if-lauseen sisään tai yhdessä sen ulkopuolelle. Molemmissa tapauksissa else-lohko jää tarpeettomaksi, koska funktiossa halutaan suorittaa joko molemmat olennaiset rivit tai ei kumpaakaan riviä.

Tässä molemmat rivit ovat if-lauseessa eikä else-lohkoa tarvita:

if (*a) {
	reverse(a + 1);
	std::cout << *a;
}

Tässä kumpikaan rivi ei ole if-lauseessa mutta else-lohkoa ei silti tarvita, koska if-lauseen sisällä on return-lause.

if (!*a) {
	return;
}
reverse(a + 1);
std::cout << *a;

Tässä ovat vastaavat koodit Javalla silloin, kun funktio palauttaa merkkijonon:

if (!a.isEmpty()) {
	return reverse(a.substring(1)) + a.charAt(0);
}
return "";
if (a.isEmpty()) {
	return "";
}
return reverse(a.substring(1)) + a.charAt(0);

Tässä on vielä pakollinen yhden rivin versio, ettei kenenkään muun tarvitse sen takia lähettää viestiä:

return a.isEmpty() ? "" : (reverse(a.substring(1)) + a.charAt(0));

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta