[C言語]入力された点数からヒストグラムを表示するプログラム[コード付き]

今回はC言語で、入力された点数を読み込んで標準出力にそのデータのヒストグラムを表示するプログラムを書いていきます。
簡単な文法のみで書いていきます。


ヒストグラムとは?

下の画像のように縦軸に度数、横軸に階級をとった統計グラフの一種で各階級の度数が伸びている柱の長さでパッと見でわかりますね。
どこに一番分布しているかもすぐわかります。


実際にコードを書いていく

まずは大まかな構想を考えましょう。
パッと思いつくのは

  • データを読み込む部分
  • ヒストグラムを表示する部分
  • 上2つの機能を制御する部分

ですかね。

ヒストグラムを読み込む部分は、ファイルから入力された場合などにも使い回せるように関数化しましょう。

他の2つは今回はmain関数の中にまとめてしまいます。


ヒストグラムを表示する関数

まずここから作りましょう。
必要な機能を箇条書きすると

  • 点数のデータが入った配列を受けとる
  • データを一つ一つ見ていき、どこの階級に振り分けるか判断する
  • 最後に振り分けの記録からヒストグラムを表示する

となります。

とりあえず特に返す値はないのでvoid型で定義しましょう。

配列の受け取りは普通に仮引数で受け取ればよいですね。

どの階級に振り分けるかですが、今回は階級を20点ごとに分けていきたいので振り分ける対象の点数を20で割った商ごとに振り分けます

具体的には
0~19点なら0、
20~39点なら1、
….
80~100点なら4番目といったふうに分けていきます。

商で振り分ける際の便利な点は、その式をそのままswitch文で使えることですね。その部分はコードを見て確認してください

switch文で分岐した先では、その階級のカウンターを1つ増加させます。
この作業をfor文で繰り返してすべてのデータに対して判断したら準備完了。

最後にヒストグラム表示です。
各階級においてprintfで階級の範囲を表示した後に、対応するカウンターの数だけforループでputchar文で*を表示していきます。
各階級が終わるたびに改行を出力してヒストグラムの体裁を整えます。

コードがこちら

void histgram(int v[N]){
    int i=0;
    
    int X[5]={};
    
    for(i=0; i<N; i++){
        switch(v[i]/20){
            case 0: X[0]++; break;
            case 1: X[1]++; break;
            case 2: X[2]++; break;
            case 3: X[3]++; break;
            default: X[4]++; break;
        }
    }
    
    for(i=0; i<4; i++){
        int n;
        printf("%2d- %2d :",20*i,20*(i+1)-1);
        for(n=0; n<X[i]; n++)
            putchar('*');
        
        printf("\n");
    }
    
    printf("80-100 :");
    
    for(i=0; i<X[4]; i++)
        putchar('*');
    
    printf("\n");
}

X[5]が各階級におけるカウンターですね。

ここで注意なのですが実は0~100って値の範囲が101なんですよね。
今回の場合だと20で割った商で考えるので、100だけは商が5になってしまいます。

それだとヒストグラムの形に違和感が感じると思うので100は80~99の階級に混ぜます。
そのためにswitch文の分岐でcase 3:の下はcase 4:ではなくdefaultにしました。これによって100がハブられずに済みましたね。

またヒストグラムを表示する部分の階級の範囲の表示は一つ一つ打ち込むのがめんどかったので計算式にしました。
20×i ~ 20×(i+1)-1ですね。

だけどここでも100がハブられているので80~100だけ個別に書きました。なんかいい方法あったかな…
そこでも改行は忘れずに!!


main関数

ここではまず点数のデータをユーザーから受け取りましょう。
今回は標準入力、つまりキーボートからの打ち込みで受け取ります。

受け取り用の配列を用意してfor文でデータの数scanfで受け取るだけですね。超簡単。

注意として今回は100点満点のテストで、ヒストグラムもそれを前提として表示するのでそこだけ気をつけましょう。

具体的には受け取る際に、入力された値が0~100かを判定して大丈夫なら良し!大丈夫じゃないならdo-while文で範囲内の値を受け取るまで繰り返せば良いですね。
判別には( date[i]>100 || date[i]<0)でいきましょう。

そんで全部のデータを受け取ったらさっき作った関数に渡しましょう。こんだけです。超簡単ですね。

int main(void) {
    int date[N];
    int i;
    
    printf("点数を入力してください (%d人分)\n",N);
    for(i=0; i<N; i++){
        do{
            printf(":");
            scanf("%d",&date[i]);
            if(date[i]>100 || date[i]<0)
                printf("正しい値を入力してください");
        }while( date[i]>100 || date[i]<0);
    }
    
    histgram(date);
    
    return 0;
}

2つのコードを組み合わせて完成です!

ちなみにNはオブジェクト形式マクロです。自分で好きな値にしましょう。
また#include <stdio.h>もわすれずに。


実際に動かしてみた

N=30で適当にデータを入力して動かしてみると、

異常無しですね。完成!!


終わりに

ここらへんはC言語を習って序盤に必ず通る課題だと思うので誰かの役に立てば幸いです。
今回始めてプログラミングの記事を書きましたが、こんな感じで大学生の課題に出てきそうなアルゴリズムなどを定期的に取り上げるのでぜひこれからもこのブログをチェックしていただけると嬉しいです!

ではまた次の記事で会いましょう!

syumokuzame

1件のコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする