探索(Searching)

・有限のデータの中から、目的のデータを探す事

	例:配列を走査して、目的の値を見つける
	  int iarray[10]={2, 5, 8, 1, 4, 7, 3, 6, 9, 0};
	                   0  1  2  3  4  5  6  7  8  9 ← index
           キー値6を探せ! indexの0からたどっていき、index7でキー値6を見つけたよ。
      探索結果 => iarray[7]が6に一致

性能(場合による)= 探索の速さ = 処理の少なさ ⇐ 繰り返し数と比較数
ハッシュ法 > 二分探索 > 線形探索

データ形式:
配列:

配列=>同じ型のデータが複数あり、名前とインデックスで表現されたもの
(double a[5]; => a[0] ~a[4]がdouble型で用意される)

レコード:

   (キー項目)|  (キーに付属した情報)
	商品番号 |     商品名      | 単価
	  A001   |  ハンバーガー   | 200 
	  A003   | チーズバーガー | 260    <= レコード形式(固定幅データ)
	 A005   | エッグサンド    | 240
          A007   | アイスコーヒー | 120
          …   |     … 	   |  …

表=テーブル(table)

「線形探索法」(逐次探索法:Linear Search Algorithm)

・データ列(レコード、配列など)を先頭から順番に一個ずつ逐次、キー値(探索値)と比較して、  見つかるまで走査する方法

 例題6-1

   レコード
      index| CarNo |  CarName  
        0  | 1003  | "MarkⅡ"
        1  | 1012  | "Chaser"
        2  | 1053  | "Mr2"
        3  | 1031  | "Rx-7"
        4  | 1021  | "Minica"
        5  | 1075  | "Legacy"

 ・CarNoで探して、車種名を出力する探索
	変数として必要なもの → indexをたどるためのカウンタ変数 i 
                 探すCarNoを保存しておく変数(キー値=探索キー)var=1053
	例)探索キーが1053で入力されたとき(P92) 結果"Mr2"と表示される
	    
	    if(var == 1053 && i<=最大データ数)
	    {
               carNameを出力
   	    }

・番兵法

	    if(var == 1024 && i<=最大データ数(N)) //アルゴリズムとしては、比較回数は2
	    {
               carNameを出力
   	    }
   ・データが見つからなかったときは最大データ数Nx2回の比較が必要
  ・最大データ数を1増やしておいて、最後に番兵を配置することで、比較回数を減らす作戦(ストラテジー)

    index| CarNo |  CarName  
        0  | 1003  | "MarkⅡ"
        1  | 1012  | "Chaser"
        2  | 1053  | "Mr2"
        3  | 1024  | "Rx-7"
        4  | 1021  | "Minica"
        5  | 1075  | "Legacy"   
     … |  …  |   …   
        N  |  XXX  | "XXXXX"
       N+1 | 1024  | -------    
             =探索キー=番兵

	while(var != 1024) //アルゴリズムとしては、比較回数は1
	{
           carNameを出力
	   i = i + 1;
   	}
	
	if(i==N+1){
	   データが見つからなかったときの処理;
	}else{
	   データが見つかった時の処理
	}
	//(N+1) x 1 Nは0以上

ーーーーーーーーーーー【複合条件】ーーーーーーーーーーーーーーーーーーーーーーーーーー

・比較の時に複数の条件を組み合わせて真偽値を決める
i>0
i<=10
・AND → 且つ  両方同時に成り立てば真  C/C++では && (shift+6)
       例:xが0以上6未満(数学だと0≦x<6)
	     xが0以上 且つ 6未満  x >= 0  &&  x < 6					

・OR  → 又は  どちらかが成り立てば真  C/C++では || (shift+\(バックスペースの左))
             例:xが0以下 または、xが6より大きい(数学だと x ≦ 0, x > 6)
 						       x <= 0 || x > 6

・Not → ~でない 条件を否定して真偽を逆転させる
	     not(x>=0) => x < 0と同値  C/C++では !(x >= 0) と書く
        !(x >= 0) == (x < 0)

剰余の演算子 % → x%3 xを3で割ったあまりが結果
割り切れる=余りが0

変数int xにおいて、
・3で割り切れて、かつ5で割り切れる x%3==0 && x%5==0  
・3で割り切れる、正ではない整数      !(x>=0) && x%3==0
				          x<0 && x%3==0
・3でも、5でも割り切れない	      !(x%3==0) && !(x%5==0)

このような複合条件が1度に書けるようになる。
ーーーーーーーーーーー【複合条件】ーーーーーーーーーーーーーーーーーーーーーーーーーーー

順次
選択(条件分岐)
繰り返し(継続条件、終了条件) 2%3==0 -> 2%3=2 -> 2==0? -> false 条件=真偽値です。
・相手にしているデータ→整列済みデータ(昇順化、降順に並んだデータ)
サンプルデータ[3, 5, 6, 8, 12, 34, 36, 37, 45, 49] 
        0  1  2  3   4   5   6   7   8   9
例)
・探索キー=37
サンプルデータ[3, 5, 6, 8, 12, 34, 36, 37, 45, 49] 
        0  1  2  3   4   5   6   7   8   9
サンプルデータ[                34, 36, 37, 45, 49] 
                         5   6   7   8   9
サンプルデータ[                34, 36, 37, 45, 49] 
                         5   6   7   8   9
サンプルデータ[                34, 36, 37        ] 
                         5   6   7  
サンプルデータ[                34, 36, 37       ] 
                         5   6   7  
サンプルデータ[                    37       ]  37発見
                             7

アルゴリズムの評価法

番兵法と比較回数とビッグオー記法

 int iarray[10]={2, 5, 8, 1, 4, 7, 3, 6, 9, 0};
	         0  1  2  3  4  5  6  7  8  9 ← index
           キー値6を探せ! indexの0からたどっていき、index7でキー値6を見つけたよ。
      探索結果 => iarray[7]が6に一致
配列数を num
探索値を key
int i = 0;
while( i < num ) ①条件その1:配列数はオーバーしていないか?
{
 iarray[i]はkeyですか?  ②条件その2:keyは見つかったか?
  Yes: indexを出力(返す:ループを抜ける)
   No: 何もしない(i = i+1)
}

複合条件で一緒に書いてみよう!

while(i<num && iarray[i] != key )
{
	i = i+1;(i++;)	
}
if(i == num)
   Yes: keyは見つかってない
    No: return( i ); //iでkeyが見つかってループ抜けてる

これをさらに、スタイリッシュに書く!
 int iarray[10]={2, 5, 8, 1, 4, 7, 3, 6, 9, 0};
	         0  1  2  3  4  5  6  7  8  9 ← index
 int   temp[11]={2, 5, 8, 1, 4, 7, 3, 6, 9, 0, ???};
                 0  1  2  3  4  5  6  7  8  9  10 ← index

keyが見つかる場合
 keyを一番最後に代入します。
 int   temp[11]={2, 5, 8, 1, 4, 7, 3, 6, 9, 0, 6};
                 0  1  2  3  4  5  6  7  8  9  10 ← index


while(iarray[i] != 6) //配列オーバーのチェックがいらなくなる 比較回数1/2
{
  i = i+1;(i++;)	
}
if(i == num)
   Yes: keyは見つかってない
    No: return( i ); //7でkeyが見つかってループ抜けてる

keyが見つかる場合
 keyを一番最後に代入します。
 int   temp[11]={2, 5, 8, 1, 4, 7, 3, 1, 9, 0, 6};
                 0  1  2  3  4  5  6  7  8  9  10 ← index


while(iarray[i] != 6) //配列オーバーのチェックがいらなくなる 比較回数1/2
{
  i = i+1;(i++;)	
}
if(i == num)
   Yes: keyは見つかってない //i==num (10)でループを抜けている
    No: return( i ); 

一般化
 keyを一番最後に代入します。
 int   temp[11]={2, 5, 8, 1, 4, 7, 3, 6, 9, 0, key}; temp[num-1]←key 番兵
                 0  1  2  3  4  5  6  7  8  9  10 ← index


while(iarray[i] != key) //配列オーバーのチェックがいらなくなる 比較回数1/2
{
  i = i+1;(i++;)	
}
if(i == num)
   Yes: keyは見つかってない
    No: return( i ); //iでkeyが見つかってループ抜けてる

「配列の最後に、番兵を置いておくことで線形探索の配列オーバーのチェックが必要なくなり、
各ステップでの比較が半分になる」

アルゴリズムの評価
 ・早い(いろんな意味で速い、早い)
  ・少ないプログラムステップで終わる(CPUの動作ステップが少ない)
 ・効率がいい(同じ動きをする者の中で一番コストが低い)
  ・メモリの使用量が少ない
 ・一般性が高い(いつでも同じように動く)
  ・いつどんな状況でやっても安定して同じような結果を返す
 ・理解のしやすさ(美しさ)
  ・誰でも実装できそうか?簡便で賢い方法か?

ビッグオー記法で大体のアルゴリズムの効率を表す

for(i=0 i<l;i++)
  for(j=0;j<m;j++)
    for(k=0;k<n;k++)
       //なんやかんや
  l=m=n=N  N*N*N  N^3の繰り返しの回数 O(N^3) Nの3乗に支配されてアルゴリズムが動く

for(i=0 i<l;i++)
  for(j=0;j<m;j++)
     //なんだかんだ
    N*N  O(N^2) オーダN二乗のアルゴリズム

 for(j=0;j<m;j++)
   N回 O(N)のアルゴリズム

ハッシュ法
   1回 O(1)のアルゴリズム
 

基本情報技術者H14秋 午前 問13

A[i](i=1~n) n個の要素があるよ
(1)A[] ={XX,XX,XX,XX ... XX}
    i=1~nまでを探索して、最小値の要素を探す
   min = A[0]
   min_i = 1;
   for(i=1;i<=n;i++)
    if(min < A[i]) ←比較
    {
            min = A[i];
            min_i = i;
     } 
  swap(A[1], A[min_i]);

O(N)×O(N) = O(N^2)
①5回比較
|1 2 3 4 5  index  
|3 4 6 1 2  要素数5
min_i = 4
min = 1
swap(1,4)
②4回比較
1 |2 3 4 5  index  
1 |4 6 3 2  
min_i = 5
min = 2
swap(2,5) indexで交換
③3回
1 2 |3 4 5  index  
1 2 |6 3 4  
min_i = 4
min = 3
swap(3,4)
④2回
1 2 3 |4 5  index  
1 2 3 |6 4
min_i = 5
min = 4
swap(4,5)
1 2 3 4 |5  index  
1 2 3 4 |6

バブルソート
1 2 3 4 5  index  
3 4 6 1 2  要素数5
3 4 1 6 2  要素数5
3 4 1 2 |6  要素数5

3 4 1 2 |6  要素数5
3 1 4 2 |6  要素数5
3 1 4 2 |6  要素数5
3 1 2 |4 6  要素数5

3 1 2 |4 6  要素数5
1 3 2 |4 6  要素数5
1 2 |3 4 6  要素数5

1 2 3 4 6 最良 O(n)
 
6 4 3 2 1 最悪  O(n^2) ←平均計算量

選択ソート
最悪 最良 平均 O(n^2)←平均計算量

挿入ソート

書いてみて
最悪の場合
最良の場合
平均 O(n^2)←平均計算量

マージソート
最悪、最良、平均 O(n・log(n))

クイックソート
最悪 O(n^2) ソート済みに近い状態が遅い
最良 O(nlogn) 
平均 O(nlogn)
logの底は2又は10
https://qiita.com/kokorinosoba/items/1c7400ca6c740fe9f1ee
https://karippu.com/stability_sort_algorithm/