Palindromin etsiminen, C vs C++/STL

empty 16.03.03 20:33

Kaksi eri funktiota testaamaan onko sana palindromi. Toinen on perinteistä C:tä, toinen näyttää kuinka näppärästi homma hoituu STL:n avulla.

 Tekstiversio  Arvo: 2 (5 ääntä)  Äänestä: +  -
//////////////////////////////////////////////////////////////////////////
/// Kaksi eri funktiota testaamaan onko sana palindromi.
///
/// Toinen on perinteistä C:tä, toinen näyttää kuinka näppärästi homma
/// hoituu STL:n avulla.
///
/// Isoja ja pieniä kirjaimia ei eritellä, ja vain kirjaimet otetaan
/// huomioon. Esim "AB 21ba.." on palindromi tämän mukaan.
///
/// Koodi on ylikommentoitua jotta siitä oppisikin jotain.
/// Ehkä vielä voisi mainita C-friikkien huojennukseksi että
/// STL-versio on huomattavasti hitaampi. C-versio
/// perustuu alkuperäisen tekstin tarkasteluun kun taas
/// STL-versio tekee siitä kopion jota se muokkaa
/// sopivaksi.
///
/// Hannu Kankaanpää 2003 (hkankaan@cc.hut.fi)
//////////////////////////////////////////////////////////////////////////

#include <string>
#include <algorithm>
#include <functional>
#include <iostream>
#include <cctype>

using namespace std;

/// C-versio.
/// Toimii niin että tekstiä lähdetään tutkimaan alusta loppuun
/// ja samalla lopusta alkuun päin ja joka askeleella verrataan
/// ovatko merkit samoja. Jos eivät ole, palautetaan 'false'. Jos
/// taas tekstistä saadaan tutkittua puolet, niin kyseessä on
/// palindromi ja palautetaan 'true'.
bool isPalindrome1(const char* text) {
        // yksi osoitin lähtee tekstin alkupäästä etenemään loppua kohti
        const char* pFront = text;
       
        // toinen osoitin lähtee lopusta alkua kohti
        const char* pBack = text + strlen(text) - 1;
       
        // alkupään merkkejä verrataan loppupään merkkeihin kunnes
        // osoittimet ohittavat toisensa.
        while (pBack >= pFront) {
                // jos alkupään osoitin osoittaa muuhun kuin kirjaimeen,
                // sitä liikutetaan eteenpäin
                if (!isalpha(*pFront)) {
                        pFront++;
                }
                // vastaava testi loppupään osoittimelle
                else if (!isalpha(*pBack)) {
                        pBack--;
                } else {
                        // jos alkupään merkki ei vastaa loppupään merkkiä
                        // niin palautetaan 'false'. toupper:ia käytetään jotta
                        // kirjaimen koolla ei olisi väliä 'a' => 'A', 'A' => 'A'
                        if (toupper(*pFront) != toupper(*pBack)) {
                                return false;
                        }
                        // liikuta kumpaakin osoittimista
                        pFront++;
                        pBack--;
                }
        }
        return true;
}

/// C++/STL-versio:
bool isPalindrome2(string text) {
        // Tässä aluksi poistetaan merkit jotka eivät ole kirjaimia.
        // remove_if() ei itsessään poista merkkejä vaan siirtää ne merkkijonon loppuun.
        // Sen takia on kutsuttava text.erasea poistamaan merkit remove_if:n palauttamasta
        // iteraattorista tekstin loppuun saakka.
        // remove_if:n kaksi ekaa parametria kertovat välin jolla merkkejä käsitellään,
        // eli tässä tapauksessa koko merkkijono alusta loppuun (begin() => end())
        // remove_if:n kolmas parametri lienee hieman hämärä. Siis not1(ptr_fun(isalpha)).
        // isalpha on osoitin funktioon, joten se täytyy kääriä luokan ympärille ptr_fun:n
        // avulla. Näin not1-predikaatti osaa käyttää sitä. not1 ottaa negaation yhden
        // argumentin vaatimasta funktiosta (isalpha).
        text.erase( remove_if(text.begin(), text.end(), not1(ptr_fun(isalpha))) , text.end());
       
        // Nyt muutetaan kaikki merkit isoiksi kirjaimiksi.
        // transform käy kaikki merkit läpi (text.begin() => text.end()) ja kutsuu
        // jokaiselle funktiota toupper. Kolmas parametri (text.begin() uudestaan)
        // kertoo minne toupper:n lopputulos (eli iso merkki) sijoitetaan. Tässä
        // tapauksessa se sijoitetaan takaisin entiselle paikalleen.
        transform(text.begin(), text.end(), text.begin(), toupper);
       
        // Sitten palautetaan vertailun tulos, eli ovatko merkit alusta loppuun
        // samoja. Aloitetaan siis text.begin():stä ja mennään text.end():iin,
        // ja verrataan näitä merkkejä loppupäästä luettaviin merkkeihin.
        // text.rbegin() siis palauttaa iteraattorin joka käy tekstin läpi lopusta
        // alkuun.
        return equal(text.begin(), text.end(), text.rbegin());
}

// Pieni testiohjelma tähän lopuksi.
int main() {
        cout << "Onko Saippuakauppias palindromi?\n";
        cout << (isPalindrome1("Saippuakauppias") ? "Juu" : "Ei") << endl;
       
        cout << "Onko \"Innostunut sonni\" palindromi?\n";
        cout << (isPalindrome2("Innostunut sonni") ? "Juu" : "Ei") << endl;
       
        cout << "Onko jee palindromi?\n";
        cout << (isPalindrome2("jee") ? "Juu" : "Ei") << endl;
}
 

empty 20:35 16.3.03 
Okei ennenkuin joku pääsee sanomaan, ei toi ensimmäinen funktio ihan C:tä ole kuitenkaan. Käsittääkseni C:ssä ei ollut const-määritettä.
ane 07:40 17.3.03 
Kyllä, C:ssä on const-määrite.
Anylo 15:59 18.3.03 
Ihan ok esimerkki STL:stä
Linkku 15:03 10.5.04 
Hienoa!