Javaで学ぶアルゴリズム　第2弾：写像

# #Javaで学ぶアルゴリズム < 写像 >

##はじめに
Javaは授業で触れただけで全くの初心者であり，何もわかっていない．なので，基本的なアルゴリズムをJavaで実装し，アルゴリズムの理解を深めるとともに，Javaにも慣れていきたい．
その第2弾として写像を扱う．

##写像
実は，中学校や高校の数学で見たことのある度数分布というのは，まさに写像である．以下にイメージ図を示す．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/5ca6609a-5ba9-6895-4f68-c4dbe4e3bdb1.png)
上図は，「0~100点までの特典を10点幅(0~9, 10~19, ..., 90~99, 100の11ランク)で区切って，各ランクの度数分布（ヒストグラム）を求める」というものである．プログラムは後に示す．
つまり，**写像とは，スケーリングのように何か別の方法でそのものを表すといったもの**であるといえる．このことから，暗号化・暗号解読にも利用される．

##実装
以下では，いくつかの例を説明し，それを実行するソースコードとそのときの出力を示す．

####例1: 度数分布（ヒストグラム）
先ほどの説明どおりである．ただし，図の描画はない．ここでは，度数分布表を出力するプログラムである．

#####ソースコード
```java:histogram.java
//2020/12/14
//@Yuya Shimizu
//---------------------------------------
//*		写像（度数分布：ヒストグラム）	*
//---------------------------------------

import java.awt.*;
import java.awt.event.*;

//パネルの設定
class histo_Panel extends Panel{
	//度数分布表描画関数
	public void paint(Graphics g){
		final int Num = 20;
		//任意のデータ
		int[] a = {35, 25, 56, 78, 43, 66, 71, 73, 80, 90, 
				   0, 73, 35, 65, 100, 78, 80, 85, 35, 50};
		int[] histo = new int[11];	//写像した後のものを格納する配列
		int i, rank;
		
		for (i=0; i<=10; i++)
			histo[i] = 0;	//0で初期化
		for (i=0; i<Num; i++){
			rank = a[i]/10;			//10分の1スケールに写像
			if (0<=rank && rank<=10)
				histo[rank]++;	//度数の加算
		}
		for (i=0; i<=10; i++){
			g.drawString(""+i*10+" - :", 10, i*20+20);	//ランクの描画
			g.drawString(""+histo[i], 50, i*20+20);		//度数の描画
		}
		
	}
}

//フレームの設定
class histo_Frame extends Frame{
	public histo_Frame(){
		setSize(200, 300);//200×300の大きさでフレームを作成
		//×ボタンを押したら終了
		addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});
		Panel p=new histo_Panel();//パネルオブジェクトpに先ほど設定したパネルを指定
		add(p);	//フレームにそのパネルを貼り付け
	}
}

//クラス
public class histogram{
	//メイン関数
	public static void main(String[] args){
		Frame w=new histo_Frame();
		w.show();
	}
}
```
#####出力
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/ba6a955d-0144-48db-f7c8-ee7922a4a67a.png)



####例2: 暗号の解読
いま，暗号文字として"KSOIDHEPZ"を解読したい．ここでの暗号化方式は次のようなイメージである．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/62b7d074-af5c-fe09-af6a-a2e6a056885f.png)
これはアルファベットの暗号化テーブルを用意し，それに基づいて暗号化しているので，そのテーブルを使えば，解読ができるということである．以下にソースコードとそのときの出力を示す．

#####ソースコード
```java:Cryptography.java
//2020/12/14
//@Yuya Shimizu
//---------------------------
//*		写像（暗号の読解）	*
//---------------------------

import java.awt.*;
import java.awt.event.*;

//パネルの設定
class crypto_Panel extends Panel{
	//暗号解読し，結果を描画する関数
	public void paint(Graphics g){
		char[] table = "QWERTYUIOPASDFGHJKLZXCVBNM?".toCharArray();
												// .toCharArray: 文字列から文字配列を生成
		char[] ango = "KSOIDHEPZ".toCharArray();	//今回解読したい暗号
		String result = "";	//結果を格納する変数
		int i, index;
		
		//tableをもとに解読
		for (i=0; i<ango.length; i++){
			if ('A'<=ango[i] && ango[i]<='Z')
				index = ango[i] - 'A';
			else
				index = 26;
			result = result + table[index];	//結果を格納
		}
		g.drawString(result, 10, 20);	//描画
	}
}

//フレームの設定
class crypto_Frame extends Frame{
	public crypto_Frame(){
		setSize(200, 100);//200×100の大きさでフレームを作成
		//×ボタンを押したら終了
		addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});
		Panel p=new crypto_Panel();//パネルオブジェクトpに先ほど設定したパネルを指定
		add(p);	//フレームにそのパネルを貼り付け
	}
}

//クラス
public class Cryptography{
	//メイン関数
	public static void main(String[] args){
		Frame w=new crypto_Frame();
		w.show();
	}
}
```
#####出力
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/b126a09c-0284-8fe1-ebf4-879d96f672ff.png)

ちなみにアルファベットを他のアルファベットに暗号化する方法としては他にもあり，例としてCaesar(シーザー)記号の紹介だけ記載しておく．以下の図を見れば何をしているかは分かる．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/9221bb1f-20d3-5c7a-8d7c-022efec91f1a.png)


####例3: XOR(排他的論理和)による暗号
名前のとおり，ビットを扱う．以下にその処理のイメージを示す．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/6b50598e-ead0-d0c9-ed5b-e3ad7cc6d602.png)
比較的簡単に実装できてしまうからこそ，安全性は怪しい．

#####ソースコード
```Crypto_XOR.java
//2020/12/14
//@Yuya Shimizu
//-----------------------------------
//*		写像（暗号の読解 - XOR）	*
//-----------------------------------

import java.awt.*;
import java.awt.event.*;

//パネルの設定
class Crypto_XOR_Panel extends Panel{
	//暗号解読し，結果を描画する関数
	public void paint(Graphics g){
		final char KCode = 0x7;	//暗号解読に必要なもの(ビット反転による暗号化と解読が可能)
		char[] ango = "FK@HUNSOJ".toCharArray(); // .toCharArray: 文字列から文字配列を生成
		String result = "";//結果を格納する変数
		int i, index;
		
		for (i=0; i<ango.length; i++){
			result = result + (char)(ango[i]^KCode);	//ビット反転により戻したものを結果に格納
		}
		g.drawString(result, 10, 20);	//描画
	}
}

//フレームの設定
class Crypto_XOR_Frame extends Frame{
	public Crypto_XOR_Frame(){
		setSize(200, 100);//200×100の大きさでフレームを作成
		//×ボタンを押したら終了
		addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});
		Panel p=new Crypto_XOR_Panel();//パネルオブジェクトpに先ほど設定したパネルを指定
		add(p);	//フレームにそのパネルを貼り付け
	}
}

//クラス
public class Crypto_XOR{
	//メイン関数
	public static void main(String[] args){
		Frame w=new Crypto_XOR_Frame();
		w.show();
	}
}
```
#####出力
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/26cbf146-1c16-601a-51c2-1d0fc892fd71.png)

##感想
今回は簡単な例を通して写像について学んだ．ロボットや画像処理に興味のある私にとっては，写像は非常に重要なものであると思っている．コンピュータの世界と現実の世界の空間のやりとりでは写像が必要となってくる場合も少なくないからである．なお，もう少し本格的な暗号には，DES(Data Encryption Standard)やFEAL(Fast Data Encipherment Algorithm)などがあるらしい．

##参考文献
Javaによるはじめてのアルゴリズム入門　　河西 朝雄　著　技術評論社