言語:JavaScriptを使って例示するけど、他の言語でチャレンジしてもOKです (概して Ruby Python Haskell あたりはかっこよくスマートに書ける)。
配列をソートする機能ぐらいはほぼどんなプログラミング言語でも既存のものが用意されていて(たとえばJSだとこれ)、 平岡も普段は「あるのならそれを使うのが正解」と思って暮らしてますが、
ここでは勉強のため、既存のライブラリを使うのを封印して自分で書いてみましょう。
枠組み
function mySort(ary) { // 名前は本家とぶつからないようにしておくのが無難
return ソートられた配列
}
// と定義しておいて
mysort([6, 5, 3, 23, 13, 21, 2, 28, 19, 12, 9, 18, 16, 7, 11, 1, 25, 26, 14, 24, 17, 22, 8, 27, 10, 29, 15, 20, 4, 30])
// のように使う
[*1..30].shuffle
で生成させたもの(重複なしの乱数列)。これが一番手軽に作れる。ソートの(アルゴリズムの)いろいろ:
今日扱うもの:
単純選択(いわゆる単純ソート)、単純交換(バブルソート)と、 少し高度なものとしてマージソートをここで扱う。
可視化について:
配列の長さ(ここでは前述の枠組みに沿って 配列 ary の長さをまず取り出すことにする)
const n = _____
最大の要素を見つける
Math.max(...ary)
Math.max.apply(null,ary)
が提示されているが、ES6 以降はスプレッド演算子(…)が使えるので、特に apply は覚えなくても大丈夫そう。あるいは
ary.reduce((v,e)=>v>e?v:e)
ただしこれらのコードは次の段階で行き詰まるので再考する必要があるだろう。
ついでに、伝統的な逐次型の書き方で求めるときにはこんなコードになる。
var ch= -9999999 // 必ず負ける数を仮チャンピオンとして置いておく
for(let i=0 ; i<n ; i++)
if(ary[i]>ch) ch=ary[i] // 下剋上 新しいチャンピオンが席につく
// ループが終わると ch に、最大の値が入ってる筈
「優勝者」を指定の席に移す
「2番目に大きい」ものを見つけるコードは誰も書きたくないので、 代わりに、この先の走査対象の範囲から、その優勝者を取り除いて、
この先もその走査範囲内での「最大の要素」を求める手順を続けられるようにする。
これが「アルゴリズム」と呼ばれる物たちの、いわばミソになる箇所。
(今日はこの部分を書いていません。考えてみましょう)
配列を決裁済データの領域と未決データの領域に分割するということでもある。
前述のコード(配列に対するメソッドを活用する)をそのまま使うとしたら、 未決データ領域に限定した部分配列を抽出してそれにメソッド適用する必要がある (Array.prototype.slice が使える)。
たとえば優勝者を配列の先頭から配置するとしたら、以下のようなコードが必要になる。
for(let i=0 ; i<n ; i++) {
let mx=Math.max(...ary.slice(i,n))
//... このように対象となる範囲を順次狭めていく。
// 優勝者データは ary[i] に置き(というのを前提としている)、
// ループの次回ではそのデータは対象範囲から外れる
}
交換、除去、追加、の書き方:
配列の中で、添字 i の要素と添字 j の要素を交換するなら、
let tmp=ary[i] ; ary[i]=ary[j] ; ary[j]=tmp
// または
[a[i],a[j]]=[a[j],a[i]]
添字 i の要素を削除(して前に詰める)なら、
ary.splice(i,1)
他に、ary.push(data)
などもチェックしておこう。
最大の要素、の場所(添字)を見つける(2. について再考)
これを繰り返す
考え方としては、
いずれでも書ける。
大枠(伝統的な3項のfor文で書くなら)
for(i=n; i>1 ; i--) // 21.7.12 修正
for(j=0 ; j<i ; j++)
j番とj+1番を比較
前回示した時に1行目をfor(i=n-1; i>1 ; i--)
と書いてたのは誤りのようです (訂正しました)。
これを可視化したアニメーションのページ: このページは50行ほどのHTMLファイルですが、 データ部を覗くとJsのコードは30行程度、 読解をすすめることは可能だと思います。
function*
という(アスタリスク付きの)定義は「ジェネレータ」と呼ばれるもので、 Webページ上でアニメーション的なコードを書くときには有用な概念です (ということに気がついている人はまだ少ないようなので解説記事があまり多くないが)。