【アルゴリズム 選択ソート】ざっくりわかるシェルスクリプト11

選択ソート

選択ソートは、未整列の配列要素の中から最小を選択し、配列先頭の整列済み列の末尾に追加していく並べ替えアルゴリズムです。
バブルソートと処理コストはほぼ同等です。
意図して選択ソートで並べ替えるといったシチュエーションはまるでありません。
木構造のヒープソートを学ぶための一里塚としての位置づけとも言われています。
データ配列の要素数が小さい場合にのみごまかして使うなどの用途しかありません。

がんばれ選択ソート!

プログラムソース

この章で使っているプログラムソースは以下にあります。
02_2SelectionSort.sh 一般的な配列の選択ソート
02_2Eval_SelectionSort.sh 擬似的な2次元配列で実装した選択ソート

選択ソートの処理手順

1.配列の先頭から小さい順(昇順)に並べる。
2.先頭から末尾までの間で最も小さい値を見つけ、一時保管場所へ複写する。
3.配列の最後尾まで行き着いたら、一時保管場所へ複写した「最も小さい値」を、「配列中で最も小さい値」とし、配列の先頭の値と交換すし、交換した要素は完了済みとしてマークする。
4.処理の再開は、マークした右隣から始める。
5.最後尾までの間で「最も小さい値」を見つけ、2番目の値と交換し、交換した要素は完了済みとしてマークする。
6.処理の再開は、マークした右隣から始める。
7.以降も同様に、n番目から末尾までで最も小さい値をn番目と入れ替えるという操作を繰り返す。

上記を末尾の一つ前の値まで繰り返せば、先頭が最も小さく末尾が最も大きい数値の列が得られる。

がんばれ選択ソート!

選択ソートのアルゴリズム

バブルソートによく似たアルゴリズムです。
選択ソートは、最小値を未整列部分の先頭(整列部分の最後尾)に移動させるだけなので、ループにおける値の交換回数が1回です。
とはいえ、最小値を探すために必要な「要素の値を繰り返し比較する回数」は、バブルソートと同じです。
結果、バブルソートよりも交換回数が少しだけ少ないので選択ソートの方が高速です。

Bash/シェルスクリプトで実装した一般的な配列で実装した選択ソート。

##
# <>selectionSort
# 選択ソート
selectionSort(){
  for((i=0;i<nElems;i++));do
    # 一番小さな値を入れるための保管場所
    min=$i;
    for((j=i+1;j<nElems;j++));do
      if (( array[min] > array[j] ));then
        min=$j;
      fi
    done
    # 交換
    tmp=${array[min]};
    array[min]=${array[i]};
    array[i]=$tmp;
    # 交換
  done
}

bash/シェルスクリプトによる疑似2次元配列の実装

#######################################
# 02_2SelectionSort.shを少しだけオブジェクティブに
# aRray[0].getValue() で値を取得できるように改変した
# 配列にIDと値を入れるだけのbashスクリプト
#######################################
##
# グローバル変数
declare -i nElems=0;
#
# <>display()  
# 配列を表示
function display(){
  for((i=0;i<nElems;i++)){
    echo -n "aRray[$i]  \
    ID: " $( aRray[$i].getID ) " \
    Value:" $( aRray[$i].getValue ) ; 
    echo "";
  }
}
##
# <>setValue() 
# セッター
function setValue() {
  #今後挿入や置き換えに備えてnElemsとは別の変数を用意しておく
  local Elem="$1";      
  local value="$2";
  eval "aRray[$Elem].getValue()      { echo "$value"; }"
}
##
# <>setID()
# セッター
function setID(){
  #今後挿入や置き換えに備えてnElemsとは別の変数を用意しておく
  local Elem="$1";      
  local ID="$2";
  eval "aRray[$Elem].getID()         { echo "$ID"; }"
}
##
# <> insert
# 配列の要素に値を代入
function insert(){
  local ID=$1;          #100からの連番
  local value=$2;       #配列に代入される要素の値
  setID     "$nElems"    "$ID";      #IDをセット
  setValue  "$nElems"    "$value";   #Valueをセット
  ((nElems++));
}
##
# <> set Array
# 配列を作成
function setArray(){
  local N=$1;           #すべての要素数
  local ID=100;         #100からの連番
  local value;          #配列に代入される要素の値
  for((i=0;i<N;i++)){
    value=$( echo $RANDOM );
    insert $((ID++)) $value;
  }
}
##
# <>bubbleSort() 
# バブルソート
# URL:https://www.youtube.com/watch?v=xli_FI7CuzA
function bubbleSort(){
  local tmp_id;
  local tmp_value;
  for((i=nElems;i>0;i--)){
    for((j=0;j<i-1;j++)){
      if(($(aRray[$j].getValue)>$(aRray[$((j+1))].getValue)));then
        # 交換
        tmp_id=$(aRray[$j].getID);
        tmp_value=$(aRray[$j].getValue);
        setID     "$j"    $(aRray[$((j+1))].getID);      #IDをセット
        setValue  "$j"    $(aRray[$((j+1))].getValue);   #Valueをセット
        setID     $((j+1))    $tmp_id;      #IDをセット
        setValue  $((j+1))    $tmp_value;   #Valueをセット
        # 交換
      fi 
    } 
  }  
}
## <>selectionSort()
# 選択ソート
# URL:https://www.youtube.com/watch?v=g-PGLbMth_g
function selectionSort(){
  local tmp_id;
  local tmp_value;
  for((i=0;i<nElems;i++)){
    min=$i;
    for((j=i+1;j<nElems;j++)){
      if(($(aRray[$min].getValue)>$(aRray[$j].getValue)));then
        min=$j;
      fi
    }
    # 交換
    tmp_id=$(aRray[$min].getID);
    tmp_value=$(aRray[$min].getValue);
    setID     "$min"    $(aRray[$i].getID);      #IDをセット
    setValue  "$min"    $(aRray[$i].getValue);   #Valueをセット
    setID     $i    $tmp_id;      #IDをセット
    setValue  $i    $tmp_value;   #Valueをセット
    # 交換
  }
}
##
# <>execSort()
# メインルーチン
function execSort(){
  local N=$1;
  setArray $N;    #配列をセット
  echo "修正前"
  display;
  #bubbleSort;     #バブルソート
  selectionSort;  #選択ソート
  echo "修正後"
  display;
}
##
# 実行
time execSort 10;
exit;

実行結果

bash-5.1$ bash 02_2Eval_SelectionSort.sh
修正前
aRray[0]      ID:  100      Value: 26575
aRray[1]      ID:  101      Value: 7756
aRray[2]      ID:  102      Value: 4820
aRray[3]      ID:  103      Value: 27520
aRray[4]      ID:  104      Value: 5972
aRray[5]      ID:  105      Value: 31315
aRray[6]      ID:  106      Value: 11637
aRray[7]      ID:  107      Value: 19155
aRray[8]      ID:  108      Value: 8036
aRray[9]      ID:  109      Value: 20576
修正後
aRray[0]      ID:  102      Value: 4820
aRray[1]      ID:  104      Value: 5972
aRray[2]      ID:  101      Value: 7756
aRray[3]      ID:  108      Value: 8036
aRray[4]      ID:  106      Value: 11637
aRray[5]      ID:  107      Value: 19155
aRray[6]      ID:  109      Value: 20576
aRray[7]      ID:  100      Value: 26575
aRray[8]      ID:  103      Value: 27520
aRray[9]      ID:  105      Value: 31315

real    0m0.219s
user    0m0.091s
sys    0m0.127s
bash-5.1$

Valueの値がソートされているのが見てわかると思います。

処理コスト

選択ソートの処理コストはバブルソートに負けず劣らず非常に高いわけですが、まずはバブルソートに続き、遅さNo.2の選択ソートの実装ができたわけです。次回からは、さらにもう少しだけ効率的なソート手法の紹介をします。

処理コストを可視化(いずれ何がどうなのかはわかります)

「ざっくり」シリーズのご紹介

【アルゴリズム 再帰】ざっくりわかるシェルスクリプト15
https://suzukiiichiro.github.io/posts/2022-10-07-01-algorithm-recursion-suzuki/
【アルゴリズム キュー】ざっくりわかるシェルスクリプト14
https://suzukiiichiro.github.io/posts/2022-10-06-01-algorithm-queue-suzuki/
【アルゴリズム スタック】ざっくりわかるシェルスクリプト13
https://suzukiiichiro.github.io/posts/2022-10-06-01-algorithm-stack-suzuki/
【アルゴリズム 挿入ソート】ざっくりわかるシェルスクリプト12
https://suzukiiichiro.github.io/posts/2022-10-05-01-algorithm-insertionsort-suzuki/
【アルゴリズム 選択ソート】ざっくりわかるシェルスクリプト11
https://suzukiiichiro.github.io/posts/2022-10-05-01-algorithm-selectionsort-suzuki/
【アルゴリズム バブルソート】ざっくりわかるシェルスクリプト10
https://suzukiiichiro.github.io/posts/2022-10-05-01-algorithm-bubblesort-suzuki/
【アルゴリズム ビッグオー】ざっくりわかるシェルスクリプト9
https://suzukiiichiro.github.io/posts/2022-10-04-01-algorithm-bigo-suzuki/
【アルゴリズム 2次元配列編】ざっくりわかるシェルスクリプト8
https://suzukiiichiro.github.io/posts/2022-10-03-01-algorithm-eval-array-suzuki/
【アルゴリズム 配列準備編】ざっくりわかるシェルスクリプト7
https://suzukiiichiro.github.io/posts/2022-10-03-01-algorithm-array-suzuki/
【アルゴリズム 配列編】ざっくりわかるシェルスクリプト6
https://suzukiiichiro.github.io/posts/2022-09-27-01-array-suzuki/
【grep/sed/awkも】ざっくりわかるシェルスクリプト5
https://suzukiiichiro.github.io/posts/2022-02-02-01-suzuki/
【grep特集】ざっくりわかるシェルスクリプト4
https://suzukiiichiro.github.io/posts/2022-01-24-01-suzuki/
【はじめから】ざっくりわかるシェルスクリプト3
https://suzukiiichiro.github.io/posts/2022-01-13-01-suzuki/
【はじめから】ざっくりわかるシェルスクリプト2
https://suzukiiichiro.github.io/posts/2022-01-12-01-suzuki/
【はじめから】ざっくりわかるシェルスクリプト1
https://suzukiiichiro.github.io/posts/2022-01-07-01-suzuki/

【TIPS】ざっくりわかるシェルスクリプト
https://suzukiiichiro.github.io/posts/2022-09-26-01-tips-suzuki/

書籍の紹介

【アルゴリズム 挿入ソート】ざっくりわかるシェルスクリプト12

【アルゴリズム 挿入ソート】ざっくりわかるシェルスクリプト12

【アルゴリズム バブルソート】ざっくりわかるシェルスクリプト10

【アルゴリズム バブルソート】ざっくりわかるシェルスクリプト10