アメリカの大学で奮闘中

アメリカの大学でプログラミングを学ぶべくコンピューターサイエンス学部に留学したものの挫折し数学科に転部した著者が、自分の挫折ポイントを踏まえて数学、プログラミング、アルゴリズムついてできる限り分かりやすく解説してみるブログ。*できる限り記事の内容は技術的な間違いをしないように気をつけていますが、もし間違いがあれば教えていただけると助かります。

片方向リストと双方向リストを大学生が解説してみた by python

以前の記事で連結リストの実装を簡単に紹介しました。

 

astrostory.hatenablog.com

 

実を言うと前回は連結リストの中でも一番シンプルで簡単な線形リストの片方向連結リストの解説を行いました。

 

ですが実際は連結リストはいくつかの種類があり、今回の記事ではそれらを解説したいと思います。

 

 

片方向リスト vs 双方向リスト

以前の記事(上に貼っている記事)で紹介した連結リストは片方向リストでした。片方向リスト先頭があってそこから最後のノードに向かって順番に接続している状態です。

 

それに対して双方向リスト先頭から最後のノードという向きだけでなく、最後から先頭の向きもノードが接続している状態です。

 

*ノードは下の図の箱のことです。

f:id:Astrostory:20220129133820p:plain

片方向連結リストの図解

f:id:Astrostory:20220129135036p:plain

双方向連結リスト

 

前回の記事のおさらいですが、(片方向)連結リストは先頭から最後のノードまでの繋がりを(最後のノードを除く)各々全てのノードが次のノードの情報を持つことで表現していました。

 

なので、双方向リストは次のノードの情報に加えて前のノードの情報も持つことで前後の繋がりを表現しています。

 

 

双方向リストを実際に実装してみましょう。

 

class LinkedList:

    class Node:

        def __init__(self, payload):

            self.payload = payload

            self.next = None

            self.prev = None

    

    def __init__(self):

        self.head = None

 

    def addNode(self, newpayload):

        newnode = LinkedList.Node(newpayload)

 

        if self.head == None:

            self.head = newnode

            return

            

        else:   #最後のノードに連結するケース

            runner = self.head

            while runner.next != None:

                runner = runner.next

            runner.next = newnode

            runner.next.prev = runner

 

links = LinkedList()

links.addNode(26)

links.addNode(99)

links.addNode(127)

links.addNode(42)

links.addNode(367)

 

*わかりやすくするために双方向リストにするために片方向リストから追加したコードをこの書体に変えています

 

コードとしては、

(片方向)連結リストはnextという変数で次のノードの情報を持っていましたが、双方向リストはそれに加えてprev(previouの略)という変数で前の情報を持っています。

 

それにより双方向リストでは先頭から最後のノードまで、最後のノードから先頭までの向きのルートも接続させることはできます。

 

連結リストの続きの記事が気になる方はこちらから

 

astrostory.hatenablog.com

 

 

参考文献

学術論文ではアウトですが..

ご勘弁を

連結リスト - Wikipedia

Gale-shapleyアルゴリズム

Gale-shapleyアルゴリズムはマッチングに関するアルゴリズムです。

 

合コンでの男女のマッチング、研修医と病院のマッチングなどのグループAとグループB、そして全ての参加者がそのマッチング対象のグループの参加者に対して順位がある場合、Gale-shapleyアルゴリズムが役立ちます。

 

これらのマッチングでは、安定マッチングと呼ばれる一対一になっている状態を目指します。

 

言葉だけの説明は難しいと思うので、実際の問題を使って解説します。

 

男女の合コンのマッチングを考えます。

 

A ... 1,2,3

B ... 2,1,3

C ... 2,3,1

 

1 ... B, A, C 

2 ... A, B, C

3 ... C, B, A

 

男性最良マッチング

男性の希望順位ができる限り反映されるマッチング(最良)を考えます。ちなみに、英語ではoptimalと言います。

 

男性の最良マッチングは男性の希望順位が反映されやすいように男性から告白します。

 

そうすると、女性1、女性2、女性3は以下のように男性がアプローチしてきます。

女性1...A

女性2...B,C

女性3...

 

でも女性2は二人の人が来ているので、自分の順位から高い方を選びます。女性2はA->B->Cの順番で希望しているので、Bを選択。

 

女性2とBがマッチしたので、Cは他の女性にアプローチします。Cの順番は2,3,1なので、女性3にアプローチします。

 

これでカップルは{(1,A)(2,B)(3,C)}とマッチングによって誕生しました。

 

ここで全員が安定マッチングしたことが分かります。

 

 

女性最良マッチング

女性の希望順位ができる限り反映されるマッチング(最良)を考えます。ちなみに、英語ではoptimalと言います。

 

上の男性マッチングの女性と男性を逆にするイメージです。

 

そうすると、男性A、男性B、男性Cは以下のように女性がアプローチしてきます

 

男性A ... 2

男性B ... 1

男性C ... 3

 

これにより{(A,2)(B,1)(C,3)}のカップルが生まれました。

 

一対一になっていることから安定マッチングになっていることも理解できます。

 

 

Spanning Tree(全域木)とは何か

今回の記事ではグラフ理論のSpanning Tree(全域木)を扱います。

 

まずそもそもグラフとは?の人はこちらの記事から入られることをお勧めします。

 

astrostory.hatenablog.com

 

 

また今回は分かりやすくするために無向グラフを使います。

全域木

全域木はかなり平たくいうと、全ての頂点が辺で結ばれている状態を満たすグラフのことを言います

 

全域木は元々のグラフの補グラフ(subgraph)になっています。

 

ちなみに、Theoremで全ての連結グラフは全域木を持つことが保証されています。

 

最小全域木

最小全域木は重り付グラフの時に、全域木のトータルの重りの和が最小になるグラフです。

 

最小全域木を求めるアルゴリズム

最小全域木を求めるアルゴリズムは主に2つです。Kruskal's Algorithm(クラスカルのアルゴリズム)とPrime Algorithm(プライムのアルゴリズム)です。

 

これらのアルゴリズムを使う際は、一旦全ての辺を消します。

 

Kruskal's Algorithm(クラスカルのアルゴリズム)

Kruskal's Algorithm(クラスカルのアルゴリズム)は全ての辺(edge)の中から小さいものを順に書き足していき、全ての頂点が結ばれるまで続けます。

f:id:Astrostory:20220101103358p:plain

 

Prime Algorithm(プライムのアルゴリズム)

Prime Algorithm(プライムのアルゴリズム)はある任意の一点からスタートして、今まで通った頂点から出ている辺(edge)の中でweight(重り)が一番小さいものを選んで線をひきます。

 

これを全ての頂点(node, vertex)が連結されるまで続けます。

 

f:id:Astrostory:20220101102747p:plain

最小全域木はできる限り合計の重りの和が小さくしたまま全ての頂点との経路が作れます。この特徴を使って実社会の問題解決に役立ててもらえればと思います。

アメリカの大学でコンピューターサイエンスを学ぶ前に知りたかったこと

僕はアメリカの大学でコンピューターサイエンス学部に入り、その後他の学部に転部しました。

 

転部した理由はシンプルに挫折したことと、学べる内容が自分の思っていたものと違ったからです。

 

その経験を元に僕がアメリカの大学に入る前に知りたかったことを書きたいと思います。

 

抽象度の高いアルゴリズムへの耐性はあるかい?

大学にもよると思いますが、一番最初にプログラミング言語そのものを学習した後、次に学ぶものはアルゴリズムやデータ構造になります。

 

アルゴリズムとはプログラムを書く際にどういう風な手順で計算をさせるかのことです。

 

例えば、RPGゲームで10歩先に落ちているみかんを拾うことをアルゴリズムに落とし込むとします。

 

一歩前に進む → 一歩前に進む →  ...  → 一歩前に進む → 地面にあるものを拾う

 

になります。

 

ですが残念ながらシステムを組む場合、これがベストの状態とは言えません。なぜなら"一歩前に進む"が多用されており、コードも読みにくく、もし他の場所で3歩先に落ちているみかんを拾うアルゴリズムが必要になった時コードを使い回せないからです。

 

この場合、以下のように考えると尚コードの行数も異なりスマートです。

n=10

n回 "一歩前に進む"を繰り返す → 地面にあるものを拾う

 

 

などのようにコードを効率化したり、有名なアルゴリズムを理解したりが必要になります。上記のものであればゲームのキャラクターがただ歩くものをイメージできるのでハードルが下がりますが、実際にコードを書くときは目に見えないものを自分でイメージしたり、あるいはイメージできずに理解してコードを書いていく必要があります。

 

以下が典型的なアルゴリズムやデータ構造になりますので、興味がある方はご覧ください。

astrostory.hatenablog.com

 

 

astrostory.hatenablog.com


astrostory.hatenablog.com

 

プログラミングを学ぶ理由は?

大学でコンピューターサイエンスを学びたい理由はなんでしょうか?

 

僕の知る限り以下の3パターンかなと思います。

1、プログラムを書くことがとことん好きな人

2、プログラミングを通して何かを作りたい人

3、コンピューターサイエンス学部を出ると就職に困らず高給取りになれと聞きつけた人

 

1の人は人並み苦労はするかもしれませんが好きなことをできているので、楽しみながら苦労を超えていけばいいと思います。

 

3の人もコンピューターサイエンス学部卒が経歴としてはいいので、将来のお金や安定性をモチベーションに頑張れるなら、それでいいと思います。

 

問題は2の人です。何かを作りたいかは今明確にできるなら明確にしておくことをおすすめします。

 

例えば、もしwebサイト、スマートフォンアプリを作りたい場合、コンピューターサイエンス学部を卒業する際にはそれらの作り方を学ぶことはできません。ただし、コンピューターサイエンスの学位を取れる人なら独学ですぐ作れるようになると思います。

 

コンピューターサイエンス学部ではあくまで、できる限りライブラリーやAPIを使わずかっちりしたシステムを作る勉強をします。

 

僕の大学なら、webサイトやモバイルアプリの作り方を勉強したい人はDigital Media Arts学部のWeb Design Concentrationなどにいくと具体的にどうやって作るかを勉強できます。

 

他の例で、ある学際領域×ITで何かをしたい場合もコンピューターサイエンスの学位は必須ではないかもしれません。

 

大学によってはBioinfomatics(生物×IT)のような学部があったりするので、そういうところに入るとミスマッチが起こらず済むかもしれません。

 

人によってはシステムそのものからガッチリ勉強したい人もいると思うので、一概には言えませんが、コンピューターサイエンス学部の最初の授業でプログラムの書き方さえ身につけてしまえばそれ以外は自分の作りたい、応用したいものにフォーカスすることが早道かもしれません。

 

卒業できるならしておこう!

1~3のいずれの人でも、できるならコンピューターサイエンス学部を卒業した方がいいとは思います。

 

まず潰しが効くからです。アメリカの高給なソフトウェアエンジニアの仕事につきたい時、コンピューターサイエンス学部卒の学歴はめちゃくちゃ有利ですし、選考でアルゴリズムやデータベースのコーディングテストもあります。

 

もう一つの理由はやっぱり知っておくことに越したことはないからです。

 

僕の体験談ですが、とあるゲームを作った時コードがかなり長くなってしまい、ずっともっと短く書けるのではだったり、うまい処理の方法があるのではと思いつつも、それがあるのかないのかすら分からずコードを書き続けました。

 

上みたいに、ループの知識がないと"前に進む"を10回書かないといけないのです。それがベストな書き方かどうかも知らずに。

 

 

最後の理由で僕はコンピューターサイエンス学部を去った後もアルゴリズムは勉強しており、このブログはその学びのアウトプットの場でもあります。

 

少し長ったらしい文章になりましたがお役に立てれば幸いです。

 

 

 

 

 

 

Geometry 相似の証明

中学の時に習ったであろう、2つの角が同じなら相似を証明していきます。

 

事前準備

そもそも相似とは

そもそも相似(similarity)の定義は...

大学で使っているテキストブックによると...

 

Two triangles are similar if their corresponding angles are equal and if their sides are in proportion.

(もし対応する角(全て)が等しくて、辺(全て)の比が等しい時、2つの三角形を相似という。)

 

それを元にして考えると、合同な三角形の場合対応する角は全て等しく、全ての辺も1:1で同じ比率になるため、合同な三角形は相似と言えます。

 

今回証明は割愛させてもらいますが、

もし△ABC~△DEFならば、△DEF~△ABC

もし△ABC~△DEFかつ△DEF~△GHIならば、△ABC~△GHI

は使っていいこととします。

 

三角形と内部の平行線

f:id:Astrostory:20201104033420p:plain

図1

次の証明の際に、"もし三角形がいずれかの辺の平行線で分割されたならば、できた三角形は元の三角形と相似である"この性質を使うため、先にここで証明しておきます。

 

証明)

△ABCとDE||BCが与えられているとする。

∠DAE = ∠BAC

∠ADE = ∠ABC, ∠AED =∠ACB (平行線の同位角)

△ABCと△ADEの対応している3つの角は全て等しい

 

平行線と比の関係より

CE:AE = BD:AD  すなわち、CE/AE = BD/AD

よって、CE/AE + AE/AE = AC/AE = BD/AD + AD/AD = AB/AD ...①

 

DF||ACを使って、同様に

BF/FC + FC/FC = BC/FC = BD/AD + AD/AD = AB/AD ...②

 

四角形DFCEが平行四辺形なので、DE=FC 

②をBC/DE =AB/AD ...③と書き換えることができる

 

①、③より、BC/DE = AB/AD = AC/CE

よって、△ABCと△ADEの対応している3つの辺の比は全て等しい

 

以上より、△ABCと△ADEは相似  □

 

 

実際の証明

それでは、今回の目的の3つの角の均さや全ての辺の割合の均一さを説明しなくても、対応する角2つの等しさで事足りることを証明していきたいと思います。

 

上の準備で赤色のところはこれからの証明で使う内容ですので、適時参照してください。

 

f:id:Astrostory:20201104041719p:plain

図2

証明)

△ABCと△ADEと∠A = ∠D、∠B = ∠E、∠C = ∠Fが与えられているとする

 

1) AB = DEの時、△ABCと△ADEは合同な三角形であるため相似

 

2)AB ≠ DEの時

AB>DE, AC>DFと仮定すると、AB、AC上にAG= DE,AH=DFを満たすGとHをとることができる。線を書き足して線分GHを作る。

 

△AGHと△DEFは合同である(∠A = ∠D,AG= DE,AH=DFより) 

∠AGH =∠DEF。

∠B = ∠Eであるため、∠AGH =∠DEF=∠B(∠ABC)

 

同位角が等しいため、GH||BC

先ほどの証明を使って,△ABCと△AGHは相似

△AGHと△DEFは合同(相似)であるため、,△ABCと△DEFは相似 □

 

 

大学の確率入門〜確率分布、確率変数、確率密度関数〜

大学で習う確率では関数で表して、微積も使います。

 

高校での確率の知識を持って大学の授業を受けた時にカルチャーショックのようなものを感じたので、そのような人が少なくなることと、確率をもっと詳しく学んでみたい人の入り口になることを願ってこの記事を書きたいと思います。

 

サイコロを使った確率 離散の場合

 

サイコロの確率について考えます。サイコロは1〜6の値をとることができます。その場合のそれぞれの確率をP(1), P(2), ... , P(6)といったように表します。

 

この0~6を一般的に確率変数といいます。確率変数とは起こりうる場合を割分けている値です。

 

確率分布とは確率変数に応じてその値をとる確率、あるいはそれをひとまとめにしたもののことです。

正直なところ、確率分布に関しては定義が少し曖昧です。大学で使っている教科書では確率、日本で買った専門書ではその確率をひとまとめにしたもの、wikipediaでは興味深いことに両方の記述があります。

もし詳しい方がいらっしゃれば下に記述していただけると幸いです。

確率分布 - Wikipedia

 

ここでは一旦、確率分布は確率変数に応じてその値をとる確率として話を進めます。

 

確率分布P(X)は下の図のようになります。

  1 2 3 4 5 6
確率変数 1 2 3 4 5 6
P(X) 1/6 1/6 1/6 1/6 1/6 1/6

 

正規分布 連続

先ほどの場合は1、2、3と確率変数が細切れになっていたのに対して、正規分布は確率変数が連続しています。

 

 

このような場合の実際の確率は積分を使って定義されます。

      P(a<=X<=b) = ∫[a,b] |p(x)|dx

 

この積分で定義されているところがみそで、もしX=0の確率を求めようとしても、a=b=0となり、確率は0になってしまいます。

 

離散のケースではそのようなことを考えなくてよいので、ここが連続の場合少し特殊です。

 

この場合のp(x)を確率密度関数と呼びます。

グラフ理論の超基礎とイメージが分かる記事

コンピューターサイエンスでも扱われるグラフ理論がどんなものなのかと、それの基礎的な知識を解説することが目的です。

 

少し特殊な数学なのでなれるまで少し時間がかかるかもです。

 

グラフと聞くとy=f(x)のグラフなどを思い浮かべるかもしれませんが、ここで紹介するグラフは”いくつかの点と、2つの点を繋ぐ線からなるもの”をいいます。

 

超ざっくりしたいいことをすれば、物同士の繋がり方を表した物で、グラフ理論は物同士がどのように繋がっているかを重要視します。

 

超基礎知識

グラフに使われている点のことを頂点(Node)といい、2つの点を繋ぐ線のことを辺(edge)と呼びます。

 

繋がり方に方向があるグラフを有向グラフ、方向がないグラフを無向グラフといいます。

 

空港と飛行機を例に考えてみます

リアルタイムでの飛行機と飛び立った空港と目的地に着目して図を考えてみてください。羽田から関空に行く飛行機の場合の向きは羽田→関空になります。それに対して、空港だけをつないでそこに直行便の有無をグラフにまとめる場合は両方の空港を行き来する便があることが前提になるので向きの情報が不必要になり無向グラフでことが足りるようになります。

 

少し理解を深めよう

ここでグラフに関して少し理解を深めてもらいたいなと思います。

 

 

 

上と下の有効グラフものは同じものでしょうか?

 

上のグラフの構成要素は

頂点={1,2,3,4,5}

辺={0→1,1→2,2→3,3→4,4→5,5→1,4→2}

です。

 

結論からいうと二つとも同じグラフです。なぜならグラフ理論は頂点同士がどのように繋がっているかを問題にしている学問で、2つの頂点が繋がっているかいないかのみが重要になります。すなわち繋がり方が同じであれば描写の違いは問題ではないのです。

 

ちなみに、上2つの図はプログラミングを使って書いているのですが、構成要素の記述のコードを書く順番を少し変えたらこの違いになりました。

 

繋がりの表し方

繋がり方の表し方は僕の自作で分かりやすくしたもので、もう少し数学的になおかつコンピューターにも理解してもらえる行列を使った表現の方法を説明したいと思います。

 

行列を習ったことがない人でも全然理解できます。

 

頂点同士の繋がりにフォーカス=隣接行列

 

どの頂点からどの辺が伸びているか=接続行列

 

この2つの行列は有向グラフか無向グラフかでも行列の中身も変わってきます。

 

下に自分が見つけた外部のリソースがあるので参考にしてみてください。

 

http://www.dais.is.tohoku.ac.jp/~shioura/teaching/ad11/ad11-09.pdf

 

 

もう少しコンピューターサイエンスチックな話として、接続リストがあります。

 

接続リストは、頂点からどの辺を移動することができるかをまとめたものです。

 

プログラミング的にはリストで集めてもいいですし、連結リストで実装してみてもいいと思います。

 

上のスライドは少し連結リストチックでした。

 

 連結リストを詳しく知りたい方はこちらへどうぞ。

astrostory.hatenablog.com

 

重り付きのグラフ

次に重り付きグラフを紹介したいと思います。

 

辺の中に入っている数字が重りの数です。重りは英語でweightといいます。

 

上のグラフまででは2つの頂点が繋がっているか、矢印はありか無しかをみてきましたが、重り付きグラフはどの程度の関係性があるのかを表します。

 

例えば飛路であれば空港と空港間の距離かもしれませんし、空港と空港間の移動にかかる値段かもしれません。

 

グラフは何を目的にするからで頂点と辺、重りは変わってきます。

 

他のグラフ理論の記事

Gale Shapleyのアルゴリズムという、一対一のマッチングに使われる手法です。グラフ理論でマッチングというと意外な気がしますが、実はマッチングはグラフ理論でよく出てくるトピックの1つです。

astrostory.hatenablog.com

 

Spanning treeと呼ばれるグラフの全ての頂点をできる限り辺を少なくして網羅するグラフの書き方のアルゴリズムを解説した記事です。

astrostory.hatenablog.com