!同値データーを安定化する、クイック・ソート

 投稿者:SECOND  投稿日:2009年 3月10日(火)18時49分59秒
  !同値データーを安定化する、クイック・ソート

! クイック・ソートは、今でも最速の部類にありながら、
!同じ評価値の、名札の順番が、ソート後に、乱れる難点があります。
!それを、拡張された下位桁の内部付加で、補償した。
!所要時間が、約1.25倍程度( ソート数 99999個 で測った) に遅く
!なりましたが、まだ、速い方です。
!
! 処理後の(ソート値)が、同値で並んでいるサンプル番号( No: )を、
! 処理前のサンプル番号( No: )の並びと、比べて下さい。
!----------------------------------------------------------
!
!テキスト・ウィンドウの、左上位置(x0,y0)と、幅(xw,yw)。
CALL SetWindowPos( WinHandle("TEXT" ),0, 100,200,800,350, 0)

SUB SetWindowPos( handle,C2, x0,y0,xw,yw, nFLG ) ! nFLG: 0=x0y0xwyw 1=x0y0 2=xwyw
   ASSIGN "user32.dll","SetWindowPos"
END SUB

!----------------------------------------------------------
LET SU=999 ! サンプルのデーター数
DIM NO_(SU), VA$(SU) ! サンプル番号、ソートするサンプルの値
DIM stb(SU) ! 同値データー順番を、安定化する拡張配列
!
LET u_$=REPEAT$("#",LEN(STR$(SU)))
LET u0$=REPEAT$("%",LEN(STR$(SU)))

SUB PRNdata(w$)
   MAT PRINT USING "      / No: "& REPEAT$(u_$& " ",SU): NO_
   MAT PRINT USING w$&     " 値: "& REPEAT$(u_$& " ",SU): VA$
END SUB

SUB Ready
!--- サンプルの作成
   RANDOMIZE 19650218 !デフォールトRND の繰返し再生
   FOR i=1 TO SU
      LET NO_(i)=i ! サンプル番号、固有のIDだが、乱れの識別のため登録順と同じにする。
      LET VA$(i)=USING$(u0$,SU*RND) ! ソートする評価値
   NEXT i
   !---
   FOR i=1 TO SU
      LET stb(i)=i ! 同値 の登録順の安定用番号( サンプルの登録順番号 )
   NEXT i
   CALL PRNdata("元の順\")
   LET t0=TIME
END SUB

SUB Result(w$)
!--- 結果のプリント
   LET t1=TIME-t0
   IF t1< 0 THEN LET t1=t1+86400
   CALL PRNdata("ソート\")
   FOR i=2 TO SU
      IF VA$(i-1)>VA$(i) THEN EXIT FOR
   NEXT i
   IF SU< i THEN PRINT w$& ": ソート時間:";t1;"sec." ELSE  PRINT w$& ": Error!"
   PRINT
END SUB

!----
CALL Ready
CALL Qsort(1,SU)
CALL Result("安定クイック")
!
CALL Ready
CALL Qsort00(1,SU)
CALL Result("通常クイック")
!
PRINT "※時間計測は、±0.05 sec 程度、無意味なバラツキ有り、"&
&& "データー数>=9999 以上で測って下さい。"
PRINT " 現在のデーター数:";SU;

!------
! 順序を安定化した、クイック・ソート
SUB Qsort(L,R)
   local i,j
   LET i=L
   LET j=R
   LET v$=VA$((L+R)/2)
   LET ss=stb((L+R)/2)
   DO
      DO WHILE VA$(i)< v$ OR (VA$(i)=v$ AND stb(i)< ss)
         LET i=i+1
      LOOP
      DO WHILE v$< VA$(j) OR (VA$(j)=v$ AND ss< stb(j))
         LET j=j-1
      LOOP
      IF j< i THEN EXIT DO
      SWAP NO_(i),NO_(j)
      SWAP VA$(i),VA$(j)
      SWAP stb(i),stb(j)
      LET i=i+1
      LET j=j-1
   LOOP UNTIL j< i
   IF L< j THEN CALL Qsort(L,j)
   IF i< R THEN CALL Qsort(i,R)
END SUB

!------
! 通常のクイック・ソート(比較用)
SUB Qsort00(L,R)
   local i,j
   LET i=L
   LET j=R
   LET v$=VA$((L+R)/2)
   DO
      DO WHILE VA$(i)< v$
         LET i=i+1
      LOOP
      DO WHILE v$< VA$(j)
         LET j=j-1
      LOOP
      IF j< i THEN EXIT DO ! 等号付 j<=i は、暴走。
      SWAP NO_(i),NO_(j)
      SWAP VA$(i),VA$(j)
      LET i=i+1
      LET j=j-1
   LOOP UNTIL j< i ! 等号付 j<=i は、低速。
   IF L< j THEN CALL Qsort00(L,j)
   IF i< R THEN CALL Qsort00(i,R)
END SUB

END
 

クイック・ソートのアニメーション

 投稿者:SECOND  投稿日:2009年 4月 1日(水)23時48分4秒
  > No.303[元記事へ]

!クイック・ソートのアニメーション
!
!写像ソートが使用できない場合、依然、最高速なクイック・ソートの手順。

!概略
! データーが、左(L)から右(R)に並んでいて、右(R)へ向かって昇順に、
! 並び替えたいとする。

!1)データー列 順番の中央位置の値を「基準値」に選ぶ。この値は、
!  全データー値の平均とも限らず、不遇にも一番大きな値や、一番小さな値に
!  選ばれる場合も含まれている。

!2)この「基準値」以上の値のデーターは、R側に、
!  この「基準値」以下の値のデーターは、L側に、2つの領域に分ける。
!  「基準値」は、1)の条件なので、分割の境界が、
!  どちらかの端に寄っていき、不均衡になる事もある。
!  各々の領域は、降順や昇順にする必要は無く、以上と以下に、分ければ良い。

!3)分割された2領域、それぞれは、新たなデーター列として、
!  上の1)2)の操作を同様に行なう。それも又、2つずつに分かれていく。
!  ・・・この繰り返しを、分割領域1つの長さが、1以下になって、
!  分割出来なくなるまで、進めると、全体のソートが終了している。


DIM VA$(100)

SUB div1time(i,j)
!----------  以上の分割を1回行なうブログラム。i=L,j=R で開始。
   LET v$=VA$((i+j)/2)
   DO
      DO WHILE VA$(i)< v$
         LET i=i+1
      LOOP
      DO WHILE v$< VA$(j)
         LET j=j-1
      LOOP
      IF j< i THEN EXIT DO ! 等号付 j<=i は、不良。連続の再帰で暴走する。
      SWAP VA$(i),VA$(j)
      LET i=i+1
      LET j=j-1
   LOOP UNTIL j< i ! 等号付 j<=i は、不適。連続の再帰で低速。
   !----------
END SUB

!上の結果のi,j (L … j)(i … R) を、
!        ↓ ↓ ↓ ↓
!   次のL,R (L … R)(L … R) として、上記の処理を行い、
!   両区間のデーター数が、各々1以下( <=1 )になるまで繰返す。


!===================
SUB QuickSort(L,R) ! 上を、連続に行なうブログラム。
   local i,j
   LET i=L
   LET j=R
   !----------
   ! 上のプログラム("---"の内側)を、ココに置いて、
   ! 再帰的に、繰返し使用。
   !----------
   CALL div1time(i,j) !これでも良い。…再帰文の分離は、local 変数に用心!
   !----------
   IF L< j THEN CALL QuickSort(L,j) !データー数1個以下( L>=j) になるまで。
   IF i< R THEN CALL QuickSort(i,R) !データー数1個以下( i>=R) になるまで。
END SUB


!========================== 上記の動作の、図解アニメーション ============
!LET samp$="079427856083621"
LET samp$="0794278069836215794278560836215806083"
LET L=1
LET R=LEN(samp$)
FOR k=L TO R
   LET VA$(k)=samp$(k:k)
NEXT k
!
SET TEXT background "Opaque"
SET TEXT font "MS ゴシック",11
SET WINDOW -1,40, 30,0
SET LINE width 2
PLOT TEXT,AT 1,1.5:"** クイック・ソートの手順 **"
LET s=26
PLOT TEXT,AT 1,s :"下線の付いた文字は、L~ R 中央位置で選ばれた「基準値」"
PLOT TEXT,AT 1,s+1 :"その「基準値」で、分割された下の段の色分、"
SET COLOR MIX(0) 0,1,1
PLOT TEXT,AT 1,s+2 :"青は「基準値」以下"
SET COLOR MIX(0) 1,1,0
PLOT TEXT,AT 13,s+2 :"黄は「基準値」以上"
SET COLOR MIX(0) 1,1,1
PLOT TEXT,AT 25,s+2 :"(無色:分割不要、確定)"
PLOT TEXT,AT 1,s+3 :"描画の順序は、再帰文としての、実行順序そのまま。"
LET s=3
!
CALL plotVA(L,R,s,L,R)
CALL GraphQS(L,R)
CALL plotVA(L,R,m+1,L,R)

SUB GraphQS(L,R) ! 分割繰返しの構造を、グラフィックに表示。
   local i,j
   LET i=L
   LET j=R
   LET s=s+1
   SET COLOR MIX(0) 1,1,1
   PLOT TEXT,AT L,s :"L"
   PLOT TEXT,AT R,s :"R"
   LET s=s+1
   !----------
   CALL div1time(i,j) !← 冒頭の(分割を1回行なう・・)文を、実際に使用。
   CALL plotVA(L,R,s,i,j)
   IF m< s THEN LET m=s
   WAIT DELAY .1 ! 描画の速さの調整。
   !----------
   IF L< j THEN CALL GraphQS(L,j)
   IF i< R THEN CALL GraphQS(i,R)
   LET s=s-2
END SUB

SUB plotVA(L,R,y,i,j)
   FOR x=L TO R
      IF L=i AND R=j THEN
         SET COLOR MIX(0) .8,.8,.8
         !SET COLOR MIX(0) 1,1,1
      ELSEIF x<=j THEN
         SET COLOR MIX(0) 0,1,1
      ELSEIF i<=x THEN
         SET COLOR MIX(0) 1,1,0
      ELSE
         SET COLOR MIX(0) 1,1,1
      END IF
      PLOT TEXT,AT x,y :VA$(x)
      IF L<>j AND ROUND((L+j)/2)=x OR i<>R AND ROUND((i+R)/2)=x THEN
         PLOT LINES:x+.2,y;x+.6,y
      END IF
   NEXT x
END SUB

END

! 付録: ※冒頭説明~付録含めて、全文をコピー貼り付け、実行する。
!-------------------------------------
! Swapの直後に、分割終了する場合で、
! 時々、どちらにも属さないデーターが、すき間を、開ける時がある。

! ※下は i=J で、swap 不要の終了ですが、iJ は、進めないと、次のL~Rが、
!  1つ長くなって、速度が落ちる。if~then swap より、無条件 swap が速い。
!  このケースは、基準のv$ の位置が、次の分割から除かれており、又、v$ 自体、
!  その位置が、移動していない、即ちソート後の位置として、確定している。

!  L       iJ       R
!  ▽▽▽▽▽▽▽▽●△△△△△△△△
!       VA$()= v$ =VA$()
!          swap
!  L      J i      R
!  ▽▽▽▽▽▽▽▽●△△△△△△△△
!          v$
!次のL------R L------R
 

戻る