2分探索法の練習

#やったこと概要
基本情報処理技術者試験のアルゴリズムを自己流で練習として書いてみました。

##他のアルゴリズムでも使う用の共通部品
線形探索法などの練習でも流用できるように作ったクラス。

###探索結果をプリントするクラス。
```java:MessagePrinter.java
/**
 * 探索結果のメッセージをプリントするクラス
 * 
 * @author hatena
 *
 */
import java.util.List;

public class MessagePrinter {

    public void printFoundMessages(int targetNumber, List<Integer> targetList) {
        System.out.println("リストの中に探索対象の数" + targetNumber + "が存在しました。");
        System.out.println("探索対象リストは" + targetList + "でした。");
        System.out.println("探索対象の数のインデックスは" + targetList.indexOf(targetNumber) + "です。");
    }

    public void printNotFoundMessages(int targetNumber, List<Integer> targetList) {
        System.out.println("リストの中に探索対象の数" + targetNumber + "は存在しませんでした。");
        System.out.println("探索対象のリストは" + targetList + "でした。");
    }

}

```

###ランダムな整数のリストを作るクラス。
`java.util.Random`クラスに指定範囲のIntStreamを返すints()メソッドがありました。
乱数に偏りがあるような気がする。。。

```java:RandomListCreator.java
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
/**
 * ランダムな正の整数のリストを作成するクラス。
 *
 * @author hatena
 *
 */
@AllArgsConstructor
public class RandomListCreator {

    public int lengthOfList;
    public int maximumNumber;//ex:50を指定したら生成されるリストは50も含む。

    /**
     * 並び替えされていない指定長さの整数リストを返すメソッド。
     *
     *
     */
    public List<Integer> createRandUnorderdList() {

        // 乱数生成用クラス
        Random rand = new Random();

      //@formatter:off
        List<Integer> unorderdRandlist =
                rand
                .ints(this.lengthOfList, 0, this.maximumNumber + 1)
                .boxed()
                .collect(Collectors.toList());
      //@formatter:on

        return unorderdRandlist;
    }

}

```

##2分探索法メイン部分
現時点で昇順のみに対応。
###2分探索法機能を備えたクラス

```java:BinSearch.java
import java.util.List;
import lombok.Data;

/**
 * 2分探索法（対象配列は現時点で昇順のみ対応）
 *
 * @author hatena
 */
@Data
public class BinSearch {

    // 先頭・中央・終端インデックス
    // 探索対象リスト、見つかったかどうかのフラグ
    private int beginIndex;
    private int midIndex;
    private int lastIndex;
    private List<Integer> targetList;
    private boolean isFound;

    // コンストラクタ。中央インデックスを先頭・終端インデックスで算出。
    public BinSearch(List<Integer> targetList) {
        this.targetList = targetList;
        this.beginIndex = 0;
        this.lastIndex = targetList.size() - 1;
        this.midIndex = (this.beginIndex + this.lastIndex) / 2;
        this.isFound = false;
    }

    /**
     * 2分探索法本体を行うメソッド
     *
     */
    public void findTargetNumber(int targetNumber) {

        // 確認するリストの先端インデックスが終端インデックス以下の間、探索を継続
        // 見つからなかったらisFoundがfalseのままでループ終了
        while (beginIndex <= lastIndex) {
            // リストの中央値とターゲット数が等しいか判定
            // 等しければisFoundを更新してループ終了。
            if (targetList.get(midIndex) == targetNumber) {
                isFound = true;
                break;

            } else if (targetList.get(midIndex) > targetNumber) {
                // リスト中央インデックス値のほうが大きいかどうか判定、確認対象インデックス更新
                lastIndex = midIndex - 1;
                midIndex = (beginIndex + lastIndex) / 2;
                continue;
            } else {
                // リスト中央インデックス値のほうが小さいかどうか判定し、確認対象インデックス更新
                beginIndex = midIndex + 1;
                midIndex = (beginIndex + lastIndex) / 2;
                continue;
            }
        }
    }
}

```

###2分探索法を実行するメインのクラス

```java:MainBinSearch.java
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import bisearch.BinSearch;
import common.MessagePrinter;
import common.RandomListCreator;

/**
 * 2分探索法実行クラス
 *
 * @author hatena
 *
 */
public class MainBinSearch {

    public static void main(String[] args) {
        // 標準入力および結果表示用インスタンス作成
        Scanner scanner = new Scanner(System.in);


        // ランダムなリスト作成に必要な情報（長さ、リスト内の最大数）をユーザーに入力させる。
        // ランダムなリストを作るクラスをインスタンス化
        System.out.print("リストの長さを正の整数で入力：");
        int lengthOfList = scanner.nextInt();
        System.out.print("リストに含める最大の数を入力：");
        int maximumNumber = scanner.nextInt();

        // ランダムな数字の昇順リストを作成
        RandomListCreator listCreator = new RandomListCreator(lengthOfList, maximumNumber);
        List<Integer> targetList = listCreator.createRandUnorderdList();
        Collections.sort(targetList);
        System.out.println("昇順のランダムな数のリストを作成しました。");

        // 探したい数を標準入力
        System.out.print("2分探索したい数を入力:");
        int targetNumber = scanner.nextInt();

        // 2分探索用のインスタンス作成、探索メソッド実行
        BinSearch binSearch = new BinSearch(targetList);
        binSearch.findTargetNumber(targetNumber);

        // メッセージ表示用のインスタンス作成
        MessagePrinter messagePrinter = new MessagePrinter();

        // 探索結果に応じてメッセージを表示
        if (binSearch.isFound()) {
            messagePrinter.printFoundMessages(targetNumber, binSearch.getTargetList());
        } else {
            messagePrinter.printNotFoundMessages(targetNumber, binSearch.getTargetList());
        }

        scanner.close();
    }
}
```

※boolean型のisFoundというフィールドは、lombokによるアクセサメソッドの自動生成だと、メソッド名がgetIsFoundやsetIsFoundというメソッド名にならないことが判明。`getIsFoundがisFound`、`setIsFoundがsetFound`というメソッド名になってしまいます（[参考](https://qiita.com/ta2roo/items/d4debe1d97d6c1ed1ed8)）。

#結果例
■ リストにターゲットの数字が存在したとき 

```
リストの長さを正の整数で入力：10
リストに含める最大の数を入力：15
昇順のランダムな数のリストを作成しました。
2分探索したい数を入力:3
リストの中に探索対象の数3が存在しました。
探索対象リストは[0, 1, 2, 3, 6, 7, 8, 12, 13, 15]でした。
探索対象の数のインデックスは3です。
```

■ リストにターゲットの数字が存在しなかったとき

```
リストの長さを正の整数で入力：10
リストに含める最大の数を入力：15
昇順のランダムな数のリストを作成しました。
2分探索したい数を入力:3
リストの中に探索対象の数3は存在しませんでした。
探索対象のリストは[1, 1, 8, 10, 10, 11, 11, 14, 14, 14]でした。
```