set でベスト5を調べる

set コンテナを使って、ベスト5を調べる部分だけをプログラムしてみます。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. ゲームの対戦成績が優秀な順に、プレイヤと成績を表示してみましょう。
    ベスト5を調べるには、常に成績をソートして保存しなければならず、表示も成績順(大きい順)に表示します。
    このようなときには set コンテナを使うのが便利です。
    set はC++に標準装備されている STL(Standard Template Library) 機能の一部です。
    前問に続いて STL を使っていますが、これを機会に習得して下さい。
  2. 新規プロジェクトから、空の Console Application を作成して、次のファイルをプロジェクトに加えて下さい。
        /*★ ベスト5を調べる     前田  稔 ★*/
        #include <iostream>
        #include <set>
        #include <string>
        using namespace std;
    
        float   point[8]= { 2.3f, 8.5f, 5.5f, 7.4f, 4.6f, 4.0f, 3.6f, 5.5f };
        char    name[8][8]=
        {  "suzuki", "tanaka", "aoki", "maeda", "yamada", "ozawa", "kojima", "satou"  };
    
        int main()
        {   set<string>s;
            set<string>::reverse_iterator p;
            char    buf[24];
            int     i;
    
            for(i=0; i<8; i++)
            {   sprintf(buf,"%6.2f %s",point[i],name[i]);
                s.insert(buf);
                if (s.size()>5)   s.erase(s.begin());
            }
            for(p=s.rbegin(); p!=s.rend(); p++)  cout << *p << endl;
            return 0;
        }
        
  3. set を使うときは set をインクルードして下さい。
    iostream にも set にも string にも「.h」が付けられていないことに注目して下さい。
    using namespace でスコープの規定値を std:: に設定します。
        #include <iostream>
        #include <set>
        #include <string>
        using namespace std;
        
  4. ゲームの成績とプレイヤの名前です。
    本来ならばゲームのプレイが終わってから結果を記録するのでしょうが、今回はテーブルで定義しています。
        float   point[8]= { 2.3f, 8.5f, 5.5f, 7.4f, 4.6f, 4.0f, 3.6f, 5.5f };
        char    name[8][8]=
        {  "suzuki", "tanaka", "aoki", "maeda", "yamada", "ozawa", "kojima", "satou"  };
        
  5. string 型の set を定義します。
    reverse_iterator p は set を逆順(大きい順)に印字する iterator(ポインタ)です。
        set<string>s;
        set<string>::reverse_iterator p;
        
  6. sprintf() で buf[] に成績とプレイヤを編集します。
    s.insert() で buf[] を set に登録します。
    set では buf[] の文字列が自動的に昇順にソートして記録されます。
    ベスト5から溢れた6位のデータ(昇順なので先頭)は削除します。
        sprintf(buf,"%6.2f %s",point[i],name[i]);
        s.insert(buf);
        if (s.size()>5)   s.erase(s.begin());
        
  7. s.rbegin() で最後部のデータから取り出して表示します。
    reverse_iterator p を使っているので、++ すると次に大きいデータにポイントされます。
        for(p=s.rbegin(); p!=s.rend(); p++)  cout << *p << endl;
        

【演習】

  1. このままでは先に 5.5 を記録した aoki よりも、後で記録した satou の 5.5 の方が上位になってしまいます。
    これを防ぐには「時刻」のデータを利用して、ソートしたときに古い日付(時刻)の方が上位になるように工夫します。
  2. サイコロ予想ゲームでベスト5を記録して下さい。
    ゲームの説明です。
    1. 乱数でサイコロを振って1~6の値を num に格納します。
    2. コンソール入力でサイコロの目を予想して ans に格納します。
    3. num と ans が一意するまで繰り返します。
    4. 何回で当たったかを調べて、ベスト5を記録します。
  3. サイコロ予想ゲームでは、回数が少ない方が上位になります。
  4. 回数が10回を超えると、ソートの順位が狂います。
    対策としては、回数を2桁(06 など)で記録します。
    または10回を超えるデータはベスト5に含めないようにします。

超初心者のプログラム入門(C/C++)