#pragma twice

KAB-studio > プログラミング > #pragma twice > 246 Version 13.10 文字列のソート

#pragma twice 246 Version 13.10 文字列のソート

前のページへ 表紙・目次へ 次のページへ

 Version 13.10
文字列のソート

「前回は、バブルソートを実際に実装してみました」
『思ったより難しくなかったよーな』
「でも自分で1から作るときっと大変だと思うよ」
『う”……』
「さて、前回の最後に、ソートの機能のバリエーションには次のようなもの
があるって紹介しました」

・配列かそれ以外か。
・各要素の型。
・比較方法。

『前回は最後の〈比較方法〉を変えてみたりしたんだね』
「そう。ということで、今回は」

・各要素の型。

「について見てみます」
『型を変えるって、たとえば int を double にとか?』
「そういう変化だと、特に大きな違いはないかな。 > で簡単に比較できる
しね」
『文字列は?』
「そうだね、文字列のソートが例としてはいいかも。たとえば、文字列の配
列をソートする場合」

void Use_DoBubbleSortToString()
{
    const char *ppchAry[5];
    ppchAry[0] = "CCC";
    ppchAry[1] = "BBB";
    ppchAry[2] = "AAA";
    ppchAry[3] = "EEE";
    ppchAry[4] = "DDD";

    // ソートします。
    DoBubbleSortToString( ppchAry, 5 );

    for( int iF1 = 0; iF1 < 5; ++iF1 )
    {
        TRACE( "%s ", ppchAry[iF1] );
    }
    TRACE( "\n" );
}

「 DoBubbleSortToString() はこれから作る関数だから」
『ソートする関数本体ってことね。文字列の配列ってこうするんだ……』
「この辺はちょっと難しいかもね。文字列ポインタは const char * だか
ら」
『その配列、ってことね』
「じゃ、次はソート本体」

// p_pchL > p_pchR なら true を、
// それ以外は false を返すようにしてください。
bool CompareTo( const char *p_pchL, const char *p_pchR )
{
    if( strcmp( p_pchL, p_pchR ) > 0 )
    {
        return true;
    }

    return false;
}

void DoBubbleSortToString( const char **p_ppchAry, int p_iSize )
{
    // 「入れ替え先」のループです。
    for( int iOut = 0; iOut < p_iSize - 1; iOut++ )
    {
        // 最後から先頭方向へのループです。
        // ただし「入れ替え先」までです。
        for( int iIn = p_iSize - 1; iOut < iIn; iIn-- )
        {
            if( CompareTo( p_ppchAry[iIn - 1], p_ppchAry[iIn] )
                == true )
            {
                // 前の方が大きいので入れ替えます。
                const char *pchTemp = p_ppchAry[iIn];
                p_ppchAry[iIn] = p_ppchAry[iIn - 1];
                p_ppchAry[iIn - 1] = pchTemp;
            }
        }
    }
}

「まずソート本体、 DoBubbleSortToString() から。注意点は4つ」

void DoBubbleSortToString( const char **p_ppchAry, int p_iSize )

「まずこの引数」
『ポインタのポインタだ……』
「難しく考えない方がいいかも」

    const char *ppchAry[5];

「これは配列だから、 [] を取ると?」
『ポインタになる、だから const char ** ってことね』
「そういうこと。次に、ループ部分」

    // 「入れ替え先」のループです。
    for( int iOut = 0; iOut < p_iSize - 1; iOut++ )
    {
        // 最後から先頭方向へのループです。
        // ただし「入れ替え先」までです。
        for( int iIn = p_iSize - 1; iOut < iIn; iIn-- )
        {

「ここはまったく変えてません」
『そういえば Version 13.09 ( No.245 ) でそういってたね』
「このループ部分は、バブルソートのアルゴリズム本体。ここを変えるとバ
ブルソートじゃなくなるし、バブルソートならここは固定」
『そーゆーもんなんだね』
「次は比較関数」

            if( CompareTo( p_ppchAry[iIn - 1], p_ppchAry[iIn] )

「バブルソートのアルゴリズムは固定なので、比較関数のコントラクトも固
定にする必要があります」
『左の方が大きかったら true を返す、ってわけね』
「そういうこと。実際の比較関数はこんな感じ」

// p_pchL > p_pchR なら true を、
// それ以外は false を返すようにしてください。
bool CompareTo( const char *p_pchL, const char *p_pchR )
{
    if( strcmp( p_pchL, p_pchR ) > 0 )
    {
        return true;
    }

    return false;
}

『 strcmp() って初見だけど、ランタイム?』
「そう、文字列比較をしてくれるランタイム関数。 strcmp() は第1引数の
方が小さいとマイナス、逆に大きいとプラス、同じなら 0 の数字が返りま
す」
『数字?』
「そう、数字。この数字は特に決まってないから〈マイナス〉ってことで
チェックするようにしてください」
『はーい』
「それと、今回は英数字しか考えないけど、それ以外の文字が混ざると面倒
な話になるから」
『え、そうなの?』
「一番簡単な話が、漢字」
『あー、そういえばソートできないよね……』
「この〈比較〉っていうのは、実はかなり複雑。構造体を使って複数のデー
タを比較したり、計算が絡んだりするとさらに複雑になるから」
『難しそう……』
「最後に、入れ替え箇所」

                // 前の方が大きいので入れ替えます。
                const char *pchTemp = p_ppchAry[iIn];
                p_ppchAry[iIn] = p_ppchAry[iIn - 1];
                p_ppchAry[iIn - 1] = pchTemp;

『つか普通じゃない、別になんか特別なことある?』
「あるよ」

                const char *pchTemp = p_ppchAry[iIn];

「この pchTemp には何が入ってる?」
『文字列』
「正確に言うと?」
『文字列のポインタつかアドレス……あ、アドレスを入れてるだけ……』
「そういうこと。ここでの入れ替えは、ポインタを入れ替えてるだけ。文字
列そのものはコピーとか全然してません」
『そういえば……』
「この文字列もそうだし、構造体をソートするときもそうだけど、この入れ
替え部分は〈まとめてコピー〉とかすると大変だから、ポインタで持って、
そのポインタだけを入れ替えます」
『文字列のコピーだと大変だよね。ってゆーか、サイズ違うんだから 
malloc() で再確保、ってゆーか CString 使った方がいいのかな?』
「そうだね。次の次の回で説明するけど、 CString を使う時には配列じゃ
ない、便利なクラスがあるからそれを使うのがいいかな」
『へー』
「文字列の配列っていうのはよく使うからね。話を戻して、基本的にこうい
う場合にはポインタだけ入れ替えます」
『コピーは大変だもんね。でも〈こういうとき〉って?』
「普通の変数だけの配列じゃなかったら、ポインタの方が楽かも。ソートは
それができるし」
『どういうこと?』
「前に言ったでしょ、ソートは単に入れ替えるだけだから、要素が増えたり
減ったりしないんです」
『 new したり delete したり、ってことを考えなくていい』
「そういうこと。だから、ソートの時にはポインタの配列が普通、って思っ
た方がいいかも」

/*
    Preview Next Story!
*/
『基本的にはこれまでと同じよね』
「ソートの機能そのものは変わらないからね」
『構造体とかクラスになるとやっぱ大変?』
「どの変数でソートするかとか、安定ソートとか色々とね」
『というわけで次回』
< Version 13.11 構造体のソート >
「につづく!」
『構造体も < とかで簡単に比較できたらいいのに』
「そういう方法もあるよ」
『え!?』
「教えるのはまだ先だけどね……」
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。