Madoka Chomado
You Are Reading

【C++11】MIT教科書Python本の練習問題をやる(1)

0

Python言語によるプログラミングイントロダクション: 世界標準MIT教科書』を買って, 読み始めました.
タイトルに大きくPythonって書いてあるけど, 中身は, Pythonに限ったことだけのものはあまり無くて, 読みやすいです.
その本にはエクササイズがいくつか載っていて, 多分Pythonでやることを想定されているのですが, Python分からないので, 好きな言語で解いていこうと思います.
(注意* タイトルにPythonってあるけど, この記事にはC++のコードしか出てきません.)

目次

  1. P23 最大の奇数を表示
  2. 書いたコード (C++11)
  3. 本の紹介

彼女です.


参考: 松屋が好き過ぎる話

P23 最大の奇数を表示

23ページ目に載っていた練習問題です.

  • ユーザに10個の正の整数の入力を促した上, その中で最も大きな奇数の値を表示する.
  • もし奇数が無かったらそれを示すメッセージを表示

楽しそう!(((o(*゚▽゚*)o)))
C++で書くぞ〜!

Sample Input

4 6 100 23 21 2 27 26 2 21

Sample Output

27

考え方

最初に, このユーザ入力のint配列を, 奇数だけにして(=偶数の要素は全部捨てて), その中から最大値を選んで表示, ということをしようと思いました.

あなたの入力値: 4, 6, 100, 23, 21, 2, 27, 26, 2, 21,
奇数のみ: 23, 21, 27, 21,
最大の奇数: 27

書いたコード (C++11)

C++11 (ラムダ式とか使ってる) で書いたので, コンパイルするときは

$ g++ -std=c++0x main.cpp

ってやります.
-std=c++0x ってつけないとコンパイルエラーになります! ><

#include <iostream>
#include <vector>
#include <algorithm>
  
// ユーザに入力させる関数
auto Input(std::vector<int> &inputs) -> void
{
    for_each(
        inputs.begin()
        , inputs.end()
        , [](int &i) -> void {std::cin >> i;}
    );
}
  
// 偶数の要素をを全部消して奇数だけ残す関数
auto RemoveAllEven(std::vector<int> &inputs) -> void
{
    inputs.erase(
        remove_if(
            inputs.begin()
            , inputs.end()
            , [](int &i) -> bool { return i%2 == 0; }
        )
        , inputs.end()
    );
}
  
auto main() -> int
{
    std::vector<int> inputs(10, 0);
      
    // ユーザに入力させ, それをinputsに格納する
    Input(inputs);
      
    // inputsの偶数の要素をを全部消して奇数だけ残す
    RemoveAllEven(inputs);
      
    if (inputs.empty())
    { // もし奇数が無かったらそれを示すメッセージを表示
        std::cout << "奇数はありませんでした" << std::endl;
    }
    else
    { // 最大の奇数を表示
        std::cout 
            << *std::max_element(inputs.begin(), inputs.end())
            << std::endl;
    }
}

(実行: Wandbox (下の方に標準入力欄))

ーーーー

私はプログラミング初心者なので, 頑張って丁寧にメモを書こうと思います!φ(*゚▽゚*)oメモメモ

1. 関数 Input

上のコードの6行目.
ユーザに入力させ, その入力値を配列にどんどん格納(入力値で中身を上書き)する関数です.

auto Input(std::vector<int> &inputs) -> void
{
    for_each(
        inputs.begin()
        , inputs.end()
        , [](int &i) -> void {std::cin >> i;}
    );
}

まず,
main関数の最初に, 入力値の格納先の inputs はこのように宣言されています.

std::vector<int> inputs(10, 0);

これは, 要素数10, すべて0で初期化されている, int型の配列のようなものです.

これを関数Inputに渡します.

ここで使っているのが for_each 文で,

for_each (最初, 最後, したい操作の関数)

みたいに使います. (最初と最後ってのはイテレータのことです)

上のコードでは

for_each(
    inputs.begin()
    , inputs.end()
    , [](int &i) -> void {std::cin >> i;}
);

って使っています!

この第三引数に渡すものは関数ですが, ここでラムダ式を書いています. (C++では、ラムダ式は、C++11からサポートされました.)
いちいち外で関数を定義しなくて便利ですね!

ということで, inputsのそれぞれの要素に対し,
std::cin >> i;
しています! (入力値で要素を上書きしてる)

あと, 上に載せたコードでは

[](int &i) -> void {std::cin >> i;}

と書いていますが, この戻り値表記(-> void)を省略して

[](int &i) {std::cin >> i;}

と書くことも出来ます.

なぜ省略できるのでしょうか?

それは, 型推論が働いているからです!
ラムダ式の戻り値の型は,明示的に書かなくても,コンパイラによって推論されます. (あと型推論の話でいくとこの引数もint i じゃなくて auto i と書いてもOKです. 引数も型推論してくれます.)

読んだ記事: C++入門 ラムダ式 (すごい難しい内容だと思いました) / C++14 のラムダ式 完全解説 前編

『キャプチャ』とかその辺の話は難しくて全く分かりません

2. 関数 RemoveAllEven

上のコード16行目.
配列(vector)を受け取って, 偶数の要素をを全部消して奇数だけ残す関数です.

auto RemoveAllEven(std::vector<int> &inputs) -> void
{
    inputs.erase(
        remove_if(
            inputs.begin()
            , inputs.end()
            , [](int &i) -> bool { return i%2 == 0; }// 述語. もし偶数要素だったら
        )
        , inputs.end()
    );
}
ユーザの入力値: 4, 6, 100, 23, 21, 2, 27, 26, 2, 21,
奇数のみ: 23, 21, 27, 21,
最大の奇数: 27

この, 一番上の『ユーザの入力値』配列から, 偶数だけ消して, 真ん中の『奇数のみ』の配列にしています.

std::remove_if(対象の範囲の最初の位置, 対象の範囲の最後の位置, 述語関数);
vector::erase(削除したい範囲の最初の位置, 削除したい範囲の最後の位置)

3. main関数

auto main() -> int
{
    std::vector<int> inputs(10, 0);
      
    // ユーザに入力させ, それをinputsに格納する
    Input(inputs);
      
    // inputsの偶数の要素をを全部消して奇数だけ残す
    RemoveAllEven(inputs);
      
    if (inputs.size() == 0)
    { // もし奇数が無かったらそれを示すメッセージを表示
        std::cout << "奇数はありませんでした" << std::endl;
    }
    else
    { // 最大の奇数を表示
        std::cout 
            << *std::max_element(inputs.begin(), inputs.end()) 
            << std::endl;
    }
}

コンテナinputsの中の最大値

*std::max_element(inputs.begin(), inputs.end())

と書いています!

vector渡してその中の最大値を返す関数を書こうとしたんですけど, ちょっと待って, もしかしたら既にあるかもしれない.
ということでググったら案の定あったので, 使いました(((o(*゚▽゚*)o)))
参照: http://www.cplusplus.com/reference/algorithm/max_element/

std::max_element(最初イテレータ, 最後イテレータ);
返り値: 最大値を指すイテレータ

なので, ‘*’付けてポインタにして最大値を取り出して表示しています

本の紹介

Python言語によるプログラミングイントロダクション: 世界標準MIT教科書

目次

  • 第1部 Python言語と計算法イントロダクション

    • 第1章 さあ,始めよう!
    • 第2章 Pythonの概要
    • 第3章 簡単な算術プログラム
    • 第4章 関数,スコープ,抽象化
    • 第5章 構造型,可変性と高階関数
    • 第6章 テストとデバッグ
    • 第7章 例外とアサーション
    • 第8章 クラスとオブジェクト指向プログラミング
  • 第2部 問題解決のための計算法

    • 第9章 計算複雑性入門
    • 第10章 いくつかの単純なアルゴリズムとデータ構造
    • 第11章 プロットとクラス
    • 第12章 確率,統計とプログラム
    • 第13章 ランダムウォークと可視化
    • 第14章 モンテカルロ・シミュレーション
    • 第15章 実験データの理解
    • 第16章 うそ,真っ赤なうそ,そして統計
  • 第3部 進んだ話題

    • 第17章 ナップサック問題とグラフ最適化問題
    • 第18章 動的計画法
    • 第19章 機械学習はやわかり

感想?

Twitterで

というのをいただいたので, 書きたいけど, まだ全然読んでない(まだP23だ!)ので, 読んだら軽いやつを書きたいです(((o(*゚▽゚*)o)))


Madoka Chomado (ちょまど)

千代田まどかです。よくちょまどと呼ばれます。Microsoft 社員。文系出身プログラマ兼マンガ家です。私の書いた記事一覧がこちらです

(2) Comments

  1. つばみ says:

    edXで授業UPされていますよ。
    だから私買ったんですが。
    頑張ろう!

    1. はい! ありがとうございます!(((o(*゚▽゚*)o))) 頑張りましょう!

コメントを残す

メールアドレスが公開されることはありません。