要素を探索する 解答ページ | Programming Place Plus 新C++編

トップページ新C++編要素を探索する

このページの概要

このページは、練習問題の解答例や解説のページです。



解答・解説

問題1 (確認★)

次のうち、結果が true になるものをすべて選んでください。a の値は 10、b の値は 20 とします。

  1. a == 10 && b == 20
  2. a == 10 && b == 10
  3. a != b || a == 0
  4. !(a == b)
  5. !(a == 10 || b == 10)
  6. a % 2 != 0 || a == 10 && b == 20


1番は、論理AND演算子(&&)を使って、2つの条件式をつないでいます(本編解説)。論理AND演算子は、まず左側のオペランド(a == 10)を評価します。これは true です。左側のオペランドが true の場合にかぎって、右側のオペランド(b == 20)の評価に進みます。こちらも true なので、全体の結果は true になります。

2番も論理AND演算子を使っています。1番と同様に、左側のオペランド(a == 10)を評価し、これは true になります。続いて、右側のオペランド(b == 10)を評価します。こちらは false になるので、全体の結果は false です。

3番は、論理OR演算子(||)を使っています(本編解説)。論理OR演算子は、まず左側のオペランド(a != b)を評価します。これは true です。左側のオペランドが true であった時点で、全体の結果は true に確定し、右側のオペランドは評価されません。

4番は、論理否定演算子(!)を使っています(本編解説)。論理否定演算子は、条件式の結果を逆(true なら false、false なら true)にします。条件式は (a == b) で、これは false ですから、全体の結果は true になります。なお、!(a == b) という条件式は、a != b と同じ意味です。

5番は、論理否定演算子を適用する対象が (a == 10 || b == 10) となっています。論理OR演算子のルールにしたがって、左側のオペランド(a == 10)が評価され、これが true なので、この条件式は true であることが確定します。この結果を、論理否定演算子によって逆にするので、全体の結果は false です。

6番は、論理OR演算子と論理AND演算子が混在しています。演算子の優先順位は、論理AND演算子のほうが高いため(本編解説)、この式は a % 2 != 0 || (a == 10 && b == 20) と同等です。オペランドの評価順としては、論理OR演算子が短絡評価であるため、まず左側のオペランド(e % 2 != 0)が評価されます。この結果は false なので、次に右側のオペランド((a == 10 && b == 20))を評価します。こちらは論理AND演算子を含んでおり、これも短絡評価なので、先に左側のオペランド(a == 10)を評価します。これは true なので、右側のオペランド(b == 20)の評価に進み、こちらも true です。論理AND演算子の両オペランドが true なので、(a == 10 && b == 20) は true です。よって、false || true が残り、最終的に結果は true ということになります。

したがって、true になるのは、1、3、4、6です。

問題2 (基本★)

std::vector<std::string> の変数から、“Hello” を探すプログラムを作成してください。


これは特定の値(“Hello”)を持った要素を探索するということなので、std::find関数で実現できます(本編解説)。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> v {
        "Good Morning",
        "Hello",
        "Good evening",
    };

    auto it = std::find(std::cbegin(v), std::cend(v), "Hello");
    if (it == std::cend(v)) {
        std::cout << "not found.\n";
    }
    else {
        std::cout << "found: " << *it << "\n";
    }
}

実行結果:

found: Hello

問題3 (基本★)

{0, 7, 9, 15, 30, 50} の要素を含んだ std::vector<int> の変数から、値が 30~40 の範囲内にある要素を探すプログラムを作成してください。


これは特定の値ではなく、条件による探索なので、std::find_if関数を使います(本編解説)。

30~40 という範囲を指定するためには、「30以上かつ 40以下」というように条件を読み解く必要があります。これが分かれば、論理AND演算子で接続すればいいと判断できるでしょう。

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v {0, 7, 9, 15, 30, 50};

    auto it = std::find_if(std::cbegin(v), std::cend(v), [](int e){ return 30 <= e && e <= 40; });
    if (it == std::cend(v)) {
        std::cout << "not found.\n";
    }
    else {
        std::cout << "found: " << *it << "\n";
    }
}

実行結果:

found: 30

問題4 (応用★★)

{0, 7, 9, 15, 30, 50} の要素を含んだ std::vector<int> の変数から、100 を割り切ることができる値を持った要素を探すプログラムを作成してください。


こちらも条件による探索なので、std::find_if関数を使います。

100 を割り切ることができるかどうかなので、要素を e とすると、100 % e == 0 が true になるものを探せばいいことになります。ここでポイントになるのは、対象の std::vector の要素に 0 が含まれていることです。e が 0 のとき 100 % e はゼロ除算になってしまうため、これを回避しなければなりません。

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v {0, 7, 9, 15, 30, 50};

    auto it = std::find_if(std::cbegin(v), std::cend(v), [](int e){ return e != 0 && 100 % e == 0; });
    if (it == std::cend(v)) {
        std::cout << "not found.\n";
    }
    else {
        std::cout << "found: " << *it << "\n";
    }
}

実行結果:

found: 50

ゼロ除算を回避するために、論理AND演算子の短絡評価を利用しています。e != 0 && 100 % e == 0 のように、左側のオペランドでゼロでないことを確認しておけば、右側のオペランドが評価されるときには、e が 0 でないことが確実になります。0 だったときには右側のオペランドは評価されることなく、全体として false であると判断されます。

問題5 (応用★★)

std::string の変数から、一番最後にあらわれる . を見つけるプログラムを作成してください。たとえば、“abc.de.fgh.ij” という文字列なら、i の手前にある . を見つけるようにしてください。


値の探索なので、std::find関数を使います。これまでと異なるのは、一番 “最後” に現れる要素を見つけたいという点です。

これはつまり、逆方向からの探索がしたいということなので、逆イテレータを使って実現します。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

int main()
{
    std::string s {"abc.de.fgh.ij"};

    auto it = std::find(std::rbegin(s), std::rend(s), '.');
    if (it == std::rend(s)) {
        std::cout << "not found.\n";
    }
    else {
        *it = '*';  // 確認のために書き換える
        std::cout << s << "\n";
    }
}

実行結果:

abc.de.fgh*ij

見つけた要素が本当に最後の . かどうか確認するために、得られたイテレータをデリファレンスして、* に書き換えるようにしました。書き換え後の文字列を出力して確認しています。要素の書き換えのために通常の逆イテレータにしましたが、要素の書き換えが不要であれば、const逆イテレータを使えます。


参考リンク



更新履歴




はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る