
解説クラスCopyClear(37)
解説クラスCopyClear(37)
2025年2月28初稿(初講)
この解説は、膨大なクラス「class CopyClear」の定義を
記載したファイル「CopyClear.h」の順番に従い解説して
行く為に今回は、「private:属性」の関数の説明を行う
事にします!今回は「sortYTypeXY0()」関数からソート系の
説明します!
この解説文章は、
解説『解説クラスCopyClear(36)』の続きです
(4-15-146)関数「void sortYTypeXY0(TypeXY* pl,
TypeXY* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYでY座標 *****/
/***** 昇順ソート(Y→X) *****/
/************************************************************************/
void CopyClear::sortYTypeXY0(
TypeXY *pl, // データの左側Ptr
TypeXY *pr // データの右側Ptr
){
TypeXY *p; // 内部Ptr:中央
TypeXY *pi; // 内部Ptr: 左
TypeXY *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
TypeXY w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXY) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXY0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXY0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXY0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXY」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、Y座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!
(B)関数「void sortYTypeXY0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXY0()」の【仮引数】
void CopyClear::sortYTypeXY0(
TypeXY *pl, // データの左側Ptr
TypeXY *pr // データの右側Ptr
){
「TypeXY* pl,」は、データ配列左端「l=left省略」
「TypeXY* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXY」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortYTypeXY0()」の【アルゴリズム】
){
TypeXY *p; // 内部Ptr:中央
TypeXY *pi; // 内部Ptr: 左
TypeXY *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
TypeXY w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXY) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXY0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXY0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXY *p; // 内部Ptr:中央
TypeXY *pi; // 内部Ptr: 左
TypeXY *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
TypeXY w; // 交換用の場所
「TypeXY* p;」は、内部ポインタ(中央用)
「TypeXY* pi;」は、内部ポインタ(左側用)
「TypeXY* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「TypeXY w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXY) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXY0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXY0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXY));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXY」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様に中央ポインタを先ず
作成してから、メンバーの座標値を取り出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y<keyY){pi++;}」で条件「pi->y<keyY」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->x<keyX){pi++;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(pi->x<keyX){pi++;}else{break;}」と、更に条件
「pi->x<keyX」≪詰り、左側X座標がキーの値未満≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->x<keyX」が不成立なら「break;」と無限ループ脱出
更に条件「pi->y==keyX」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY<pj->y){pj--;}」で
条件「keyY<pj->y」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyY==pj->y){if(keyX<pj->x){pj--;}else{
break;}}」と条件「pi->y==keyX」とY座標が同値の時、
「if(keyX<pj->x){pj--;}else{break;}}」と、更に条件
「keyX<pj->x」≪詰り、右側X座標がキーの値越え≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「keyX<pj->x」が不成立なら「break;」と無限ループ脱出
更に条件「keyY==pj->y」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortYTypeXY0()」では、
座標の比較をY座標を比較しますが、Y座標とキーが同じ
場合は、X座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXY0(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXY0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXY0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXY0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-147)関数「void sortYTypeXY1(TypeXY* pl,
TypeXY* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYでY座標 *****/
/***** 降順ソート(Y→X) *****/
/************************************************************************/
void CopyClear::sortYTypeXY1(
TypeXY *pl, // データの左側Ptr
TypeXY *pr // データの右側Ptr
){
TypeXY *p; // 内部Ptr:中央
TypeXY *pi; // 内部Ptr: 左
TypeXY *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
TypeXY w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXY) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXY1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXY1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXY1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXY」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
比較は、Y座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!
(B)関数「void sortYTypeXY1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXY1()」の【仮引数】
void CopyClear::sortYTypeXY1(
TypeXY *pl, // データの左側Ptr
TypeXY *pr // データの右側Ptr
){
「TypeXY* pl,」は、データ配列左端「l=left省略」
「TypeXY* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXY」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortYTypeXY1()」の【アルゴリズム】
){
TypeXY *p; // 内部Ptr:中央
TypeXY *pi; // 内部Ptr: 左
TypeXY *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
TypeXY w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXY) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXY1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXY1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXY *p; // 内部Ptr:中央
TypeXY *pi; // 内部Ptr: 左
TypeXY *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
TypeXY w; // 交換用の場所
「TypeXY* p;」は、内部ポインタ(中央用)
「TypeXY* pi;」は、内部ポインタ(左側用)
「TypeXY* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「TypeXY w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXY) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXY1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXY1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXY));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXY」と座標値(X座標・Y座標)のメン
バーとして使用するので理解し易い様に中央ポインタを先ず
作成してから、メンバーの座標値を取り出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y>keyY){pi++;}」で条件「pi->y>keyY」≪
詰り、左側X座標がキーの値越え≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->x>keyX){pi++;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(pi->x>keyX){pi++;}else{break;}」と、更に条件
「pi->x>keyX」≪詰り、左側X座標がキーの値越え≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->x>keyX」が不成立なら「break;」と無限ループ脱出
更に条件「pi->y==keyX」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY>pj->y){pj--;}」で
条件「keyY>pj->y」≪詰り、右側X座標がキーの値越え≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyY==pj->y){if(keyX>pj->x){pj--;}else{
break;}}」と条件「pi->y==keyX」とY座標が同値の時、
「if(keyX>pj->x){pj--;}else{break;}}」と、更に条件
「keyX>pj->x」≪詰り、右側X座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「keyX>pj->x」が不成立なら「break;」と無限ループ脱出
更に条件「keyY==pj->y」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortYTypeXY1()」では、
座標の比較をY座標を比較しますが、Y座標とキーが同じ
場合は、X座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXY1(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXY1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXY1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXY1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-148)関数「void sortXTypeXYF0(
TypeXYF* pl,TypeXYF* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYFでX座標 *****/
/***** 昇順(X→Y) *****/
/************************************************************************/
void CopyClear::sortXTypeXYF0(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYF0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYF0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYF0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYF」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、X座標の大小を元に比較し、比較時にX座標が同値
ならば、Y座標の大小を比較します!
(B)関数「void sortXTypeXYF0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYF0()」の【仮引数】
void CopyClear::sortXTypeXYF0(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
「TypeXYF* pl,」は、データ配列左端「l=left省略」
「TypeXYF* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYF」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortXTypeXYF0()」の【アルゴリズム】
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYF0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYF0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
「TypeXYF* p;」は、内部ポインタ(中央用)
「TypeXYF* pi;」は、内部ポインタ(左側用)
「TypeXYF* pj;」は、内部ポインタ(右側用)
「float keyX;」は、中央の値(キー比較用のX座標)
「float keyY;」は、中央の値(キー比較用のY座標)
「TypeXYF w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYF0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYF0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYF));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYF」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x<keyX){pi++;}」で条件「pi->x<keyX」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y<keyY){pi++;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(pi->y<keyY){pi++;}else{break;}」と、更に条件
「pi->y<keyY」≪詰り、左側Y座標がキーの値未満≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->y<keyY」が不成立なら「break;」と無限ループ脱出
更に条件「pi->x==keyX」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX<pj->x){pj--;}」で
条件「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyX==pj->x){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(keyY<pj->y){pj--;}else{break;}}」と、更に条件
「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「pi->y<keyY」が不成立なら「break;」と無限ループ脱出
更に条件「keyX==pj->x」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortXTypeXYF0()」では、
座標の比較をX座標を比較しますが、X座標とキーが同じ
場合は、Y座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYF0(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYF0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYF0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYF0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-149)関数「void sortXTypeXYF1(
TypeXYF* pl,TypeXYF* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYFでX座標 *****/
/***** 降順(X→Y) *****/
/************************************************************************/
void CopyClear::sortXTypeXYF1(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYF1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYF1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYF1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYF」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
ここでの座標比較は、X座標の大小を元に比較し、
比較時にX座標が同値ならば、Y座標の大小を比較します!
(B)関数「void sortXTypeXYF1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYF1()」の【仮引数】
void CopyClear::sortXTypeXYF1(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
「TypeXYF* pl,」は、データ配列左端「l=left省略」
「TypeXYF* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYF」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortXTypeXYF1()」の【アルゴリズム】
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYF1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYF1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
「TypeXYF* p;」は、内部ポインタ(中央用)
「TypeXYF* pi;」は、内部ポインタ(左側用)
「TypeXYF* pj;」は、内部ポインタ(右側用)
「float keyX;」は、中央の値(キー比較用のX座標)
「float keyY;」は、中央の値(キー比較用のY座標)
「TypeXYF w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYF1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYF1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYF));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYF」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x>keyX){pi++;}」で条件「pi->x>keyX」≪
詰り、左側X座標がキーの値越え≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y>keyY){pi++;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(pi->y>keyY){pi++;}else{break;}」と、更に条件
「pi->y>keyY」≪詰り、左側Y座標がキーの値越え≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->y>keyY」が不成立なら「break;」と無限ループ脱出
更に条件「pi->x==keyX」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX<pj->x){pj--;}」で
条件「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyX==pj->x){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(keyY<pj->y){pj--;}else{break;}}」と、更に条件
「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「pi->y>keyY」が不成立なら「break;」と無限ループ脱出
更に条件「keyX==pj->x」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortXTypeXYF1()」では、
座標の比較をX座標を比較しますが、X座標とキーが同じ
場合は、Y座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYF1(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYF1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYF1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYF1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-150)関数「void sortYTypeXYF0(
TypeXYF* pl,TypeXYF* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYFでY座標 *****/
/***** 昇順(Y→X) *****/
/************************************************************************/
void CopyClear::sortYTypeXYF0(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYF0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYF0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYF0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYF」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、X座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!
(B)関数「void sortYTypeXYF0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYF0()」の【仮引数】
void CopyClear::sortYTypeXYF0(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
「TypeXYF* pl,」は、データ配列左端「l=left省略」
「TypeXYF* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYF」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortYTypeXYF0()」の【アルゴリズム】
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYF0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYF0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
「TypeXYF* p;」は、内部ポインタ(中央用)
「TypeXYF* pi;」は、内部ポインタ(左側用)
「TypeXYF* pj;」は、内部ポインタ(右側用)
「float keyX;」は、中央の値(キー比較用のX座標)
「float keyY;」は、中央の値(キー比較用のY座標)
「TypeXYF w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYF0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYF0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYF));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYF」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y<keyY){pi++;}」で条件「pi->y<keyY」≪
詰り、左側Y座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->y<keyY){pi++;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(pi->x<keyX){pi++;}else{break;}」と、更に条件
「pi->x<keyX」≪詰り、左側X座標がキーの値未満≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->x<keyX」が不成立なら「break;」と無限ループ脱出
更に条件「pi->y==keyY」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY<pj->y){pj--;}」で
条件「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyY==pj->y){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(keyY<pj->y){pj--;}else{break;}}」と、更に条件
「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「keyX<pj->x」が不成立なら「break;」と無限ループ脱出
更に条件「keyY==pj->y」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortYTypeXYF0()」では、
座標の比較をY座標を比較しますが、Y座標とキーが同じ
場合は、X座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYF0(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYF0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYF0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYF0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-151)関数「void sortYTypeXYF1(
TypeXYF* pl,TypeXYF* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYFでY座標 *****/
/***** 降順(Y→X) *****/
/************************************************************************/
void CopyClear::sortYTypeXYF1(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYF1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYF1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYF1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYF」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
比較は、X座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!
(B)関数「void sortYTypeXYF1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYF1()」の【仮引数】
void CopyClear::sortYTypeXYF1(
TypeXYF *pl, // データの左側Ptr
TypeXYF *pr // データの右側Ptr
){
「TypeXYF* pl,」は、データ配列左端「l=left省略」
「TypeXYF* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYF」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortYTypeXYF1()」の【アルゴリズム】
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYF1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYF1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYF *p; // 内部Ptr:中央
TypeXYF *pi; // 内部Ptr: 左
TypeXYF *pj; // 内部Ptr: 右
float keyX; // 中央の値:X
float keyY; // 中央の値:Y
TypeXYF w; // 交換用の場所
「TypeXYF* p;」は、内部ポインタ(中央用)
「TypeXYF* pi;」は、内部ポインタ(左側用)
「TypeXYF* pj;」は、内部ポインタ(右側用)
「float keyX;」は、中央の値(キー比較用のX座標)
「float keyY;」は、中央の値(キー比較用のY座標)
「TypeXYF w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYF) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYF1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYF1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYF));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYF」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y>keyY){pi++;}」で条件「pi->y>keyY」≪
詰り、左側Y座標がキーの値越え≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->x>keyX){pi++;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(pi->x>keyX){pi++;}else{break;}」と、更に条件
「pi->x>keyX」≪詰り、左側X座標がキーの値越え≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->x>keyX」が不成立なら「break;」と無限ループ脱出
更に条件「pi->y==keyY」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY>pj->y){pj--;}」で
条件「keyY>pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyY==pj->y){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(keyX>pj->x){pj--;}else{break;}}」と、更に条件
「keyX>pj->x」≪詰り、右側X座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「pi->x>keyX」が不成立なら「break;」と無限ループ脱出
更に条件「keyY==pj->y」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortYTypeXYF1()」では、
座標の比較をX座標を比較しますが、X座標とキーが同じ
場合は、Y座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYF1(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYF1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYF1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYF1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-152)関数「void sortXTypeXYD0(
TypeXYD* pl,TypeXYD* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYDでX座標 *****/
/***** 昇順ソート(X→Y) *****/
/************************************************************************/
void CopyClear::sortXTypeXYD0(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYD0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYD0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYD0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYD」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、X座標の大小を元に比較し、比較時にX座標が同値
ならば、Y座標の大小を比較します!
(B)関数「void sortXTypeXYD0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYD0()」の【仮引数】
void CopyClear::sortXTypeXYD0(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
「TypeXYD* pl,」は、データ配列左端「l=left省略」
「TypeXYD* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYD」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortXTypeXYD0()」の【アルゴリズム】
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYD0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYD0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
「TypeXYD* p;」は、内部ポインタ(中央用)
「TypeXYD* pi;」は、内部ポインタ(左側用)
「TypeXYD* pj;」は、内部ポインタ(右側用)
「double keyX;」は、中央の値(キー比較用のX座標)
「double keyY;」は、中央の値(キー比較用のY座標)
「TypeXYD w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYD0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYD0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYD));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYD」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x<keyX){pi++;}」で条件「pi->x<keyX」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y<keyY){pi++;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(pi->y<keyY){pi++;}else{break;}」と、更に条件
「pi->y<keyY」≪詰り、左側Y座標がキーの値未満≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->y<keyY」が不成立なら「break;」と無限ループ脱出
更に条件「pi->x==keyX」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX<pj->x){pj--;}」で
条件「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyX==pj->x){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(keyY<pj->y){pj--;}else{break;}}」と、更に条件
「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「pi->y<keyY」が不成立なら「break;」と無限ループ脱出
更に条件「keyX==pj->x」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortXTypeXYD0()」では、
座標の比較をX座標を比較しますが、X座標とキーが同じ
場合は、Y座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYD0(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYD0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYD0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYD0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-153)関数「void sortXTypeXYD1(
TypeXYD* pl,TypeXYD* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYDでX座標 *****/
/***** 降順ソート(X→Y) *****/
/************************************************************************/
void CopyClear::sortXTypeXYD1(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYD1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYD1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYD1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYD」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
ここでの座標比較は、X座標の大小を元に比較し、
比較時にX座標が同値ならば、Y座標の大小を比較します!
(B)関数「void sortXTypeXYD1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYD1()」の【仮引数】
void CopyClear::sortXTypeXYD1(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
「TypeXYD* pl,」は、データ配列左端「l=left省略」
「TypeXYD* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYD」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortXTypeXYD1()」の【アルゴリズム】
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYD1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYD1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
「TypeXYD* p;」は、内部ポインタ(中央用)
「TypeXYD* pi;」は、内部ポインタ(左側用)
「TypeXYD* pj;」は、内部ポインタ(右側用)
「double keyX;」は、中央の値(キー比較用のX座標)
「double keyY;」は、中央の値(キー比較用のY座標)
「TypeXYD w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYD1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYD1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYD));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYD」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x>keyX){pi++;}」で条件「pi->x>keyX」≪
詰り、左側X座標がキーの値越え≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y>keyY){pi++;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(pi->y>keyY){pi++;}else{break;}」と、更に条件
「pi->y>keyY」≪詰り、左側Y座標がキーの値越え≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->y>keyY」が不成立なら「break;」と無限ループ脱出
更に条件「pi->x==keyX」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX<pj->x){pj--;}」で
条件「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyX==pj->x){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->x==keyX」とX座標が同値の時、
「if(keyY<pj->y){pj--;}else{break;}}」と、更に条件
「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「pi->y>keyY」が不成立なら「break;」と無限ループ脱出
更に条件「keyX==pj->x」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortXTypeXYD1()」では、
座標の比較をX座標を比較しますが、X座標とキーが同じ
場合は、Y座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYD1(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYD1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYD1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYD1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-154)関数「void sortYTypeXYD0(
TypeXYD* pl,TypeXYD* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYDでY座標 *****/
/***** 昇順ソート(Y→X) *****/
/************************************************************************/
void CopyClear::sortYTypeXYD0(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYD0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYD0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYD0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYD」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、X座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!
(B)関数「void sortYTypeXYD0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYD0()」の【仮引数】
void CopyClear::sortYTypeXYD0(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
「TypeXYD* pl,」は、データ配列左端「l=left省略」
「TypeXYD* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYD」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortYTypeXYD0()」の【アルゴリズム】
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYD0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYD0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
「TypeXYD* p;」は、内部ポインタ(中央用)
「TypeXYD* pi;」は、内部ポインタ(左側用)
「TypeXYD* pj;」は、内部ポインタ(右側用)
「double keyX;」は、中央の値(キー比較用のX座標)
「double keyY;」は、中央の値(キー比較用のY座標)
「TypeXYD w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYD0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYD0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYD));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYD」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y<keyY){pi++;}」で条件「pi->y<keyY」≪
詰り、左側Y座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->y<keyY){pi++;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(pi->x<keyX){pi++;}else{break;}」と、更に条件
「pi->x<keyX」≪詰り、左側X座標がキーの値未満≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->x<keyX」が不成立なら「break;」と無限ループ脱出
更に条件「pi->y==keyY」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY<pj->y){pj--;}」で
条件「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyY==pj->y){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(keyY<pj->y){pj--;}else{break;}}」と、更に条件
「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「keyX<pj->x」が不成立なら「break;」と無限ループ脱出
更に条件「keyY==pj->y」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortYTypeXYD0()」では、
座標の比較をY座標を比較しますが、Y座標とキーが同じ
場合は、X座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYD0(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYD0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYD0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYD0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-155)関数「void sortYTypeXYD1(
TypeXYD* pl,TypeXYD* pr){・・・}」
/************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYDでY座標 *****/
/***** 降順ソート(Y→X) *****/
/************************************************************************/
void CopyClear::sortYTypeXYD1(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYD1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYD1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYD1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYD」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
比較は、X座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!
(B)関数「void sortYTypeXYD1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYD1()」の【仮引数】
void CopyClear::sortYTypeXYD1(
TypeXYD *pl, // データの左側Ptr
TypeXYD *pr // データの右側Ptr
){
「TypeXYD* pl,」は、データ配列左端「l=left省略」
「TypeXYD* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYD」≪
解説『解説クラスSupport』の(2-1)
座標組用データ構造「座標」で解説≫
(D)関数「sortYTypeXYD1()」の【アルゴリズム】
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYD1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYD1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYD *p; // 内部Ptr:中央
TypeXYD *pi; // 内部Ptr: 左
TypeXYD *pj; // 内部Ptr: 右
double keyX; // 中央の値:X
double keyY; // 中央の値:Y
TypeXYD w; // 交換用の場所
「TypeXYD* p;」は、内部ポインタ(中央用)
「TypeXYD* pi;」は、内部ポインタ(左側用)
「TypeXYD* pj;」は、内部ポインタ(右側用)
「double keyX;」は、中央の値(キー比較用のX座標)
「double keyY;」は、中央の値(キー比較用のY座標)
「TypeXYD w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYD) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYD1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYD1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYD));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYD」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y>keyY){pi++;}」で条件「pi->y>keyY」≪
詰り、左側Y座標がキーの値越え≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->x>keyX){pi++;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(pi->x>keyX){pi++;}else{break;}」と、更に条件
「pi->x>keyX」≪詰り、左側X座標がキーの値越え≫の間
「pi++;」ポインタを右側に移動を繰り返す、そして条件
「pi->x>keyX」が不成立なら「break;」と無限ループ脱出
更に条件「pi->y==keyY」が不成立なら「break;」と無限
ループ脱出、
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY>pj->y){pj--;}」で
条件「keyY>pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「else if(keyY==pj->y){if(keyY<pj->y){pj--;}else{
break;}}」と条件「pi->y==keyY」とY座標が同値の時、
「if(keyX>pj->x){pj--;}else{break;}}」と、更に条件
「keyX>pj->x」≪詰り、右側X座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして条件
「pi->x>keyX」が不成立なら「break;」と無限ループ脱出
更に条件「keyY==pj->y」が不成立なら「break;」と無限
ループ脱出、★備考★この関数「sortYTypeXYD1()」では、
座標の比較をX座標を比較しますが、X座標とキーが同じ
場合は、Y座標で比較する事は理解していますね!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYD1(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYD1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYD1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYD1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-156)関数「void sortXTypeXYHV0(
TypeXYHV* pl,TypeXYHV* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:座標昇順ソート:データ=TypeXYHVでX座標*****/
/***** 昇順(X座標→Y座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortXTypeXYHV0(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHV0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHV0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYHV0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHV」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、X座標の大小を元に比較し、比較時にX座標が同値
ならば、Y座標の大小を比較します!更にXY座標が同値の
時は、水平幅×垂直幅≪詰り、面積≫の降順≪大きい方から
小さい方へ整列≫でソートする関数です!
(B)関数「void sortXTypeXYHV0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYHV0()」の【仮引数】
void CopyClear::sortXTypeXYHV0(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
「TypeXYHV* pl,」は、データ配列左端「l=left省略」
「TypeXYHV* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHV」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortXTypeXYHV0()」の【アルゴリズム】
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHV0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHV0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
「TypeXYHV* p;」は、内部ポインタ(中央用)
「TypeXYHV* pi;」は、内部ポインタ(左側用)
「TypeXYHV* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHV w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHV0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHV0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHV));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHV」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x<keyX){pi++;}」で条件「pi->x<keyX」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y<keyY){pi++;}else
if(pi->y==keyY){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->x==keyX」とX座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としX座標が同値なら、Y座標で比較し条件
「pi->y<keyY」≪詰り、左側Y座標がキーの値未満≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX<pj->x){pj--;}」で
条件「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyX==pj->x」とX座標が同値なら、Y座標で比較し
条件「keyY<pj->y」≪詰り、左側Y座標がキーの値越え≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYHV0(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYHV0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYHV0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYHV0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-157)関数「void sortXTypeXYHV1(
TypeXYHV* pl,TypeXYHV* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYHVでX座標 *****/
/***** 降順(X座標→Y座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortXTypeXYHV1(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHV1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHV1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYHV1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHV」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
ここでの座標比較は、X座標の大小を元に比較し、
比較時にX座標が同値ならば、Y座標の大小を比較します!
更にXY座標が同値の時は、水平幅×垂直幅≪詰り、面積≫
の降順≪大きい方から小さい方へ整列≫でソートする関数
です!
(B)関数「void sortXTypeXYHV1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYHV1()」の【仮引数】
void CopyClear::sortXTypeXYHV1(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
「TypeXYHV* pl,」は、データ配列左端「l=left省略」
「TypeXYHV* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHV」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortXTypeXYHV1()」の【アルゴリズム】
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHV1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHV1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
「TypeXYHV* p;」は、内部ポインタ(中央用)
「TypeXYHV* pi;」は、内部ポインタ(左側用)
「TypeXYHV* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHV w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHV1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHV1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHV));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHV」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x>keyX){pi++;}」で条件「pi->x>keyX」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y>keyY){pi++;}else
if(pi->y==keyY){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->x==keyX」とX座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としX座標が同値なら、Y座標で比較し条件
「pi->y>keyY」≪詰り、左側Y座標がキーの値越え≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値未満≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX>pj->x){pj--;}」で
条件「keyX>pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyX==pj->x」とX座標が同値なら、Y座標で比較し
条件「keyY>pj->y」≪詰り、左側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYHV1(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYHV1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYHV1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYHV1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
★★特注「note編集機能不具合」★★
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」と
コピペでテキストを記載したら、
「keyH=p->h;keyV=p->v;keyHV=keyHkeyV;」と
等と主に「*」が消える事が多々ありますので注意して手作業
で修正して居るが、全て修正出来て無い部分が有る事に留意
して読んで頂きたい!必ず、【<>code】機能で生の
テキストを必ず参考にして下さい!!
(4-15-158)関数「void sortYTypeXYHV0(
TypeXYHV* pl,TypeXYHV* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYHVでY座標 *****/
/***** 昇順(Y座標→X座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortYTypeXYHV0(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHV0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHV0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYHV0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHV」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、Y座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!更にXY座標が同値の
時は、水平幅×垂直幅≪詰り、面積≫の降順≪大きい方から
小さい方へ整列≫でソートする関数です!
(B)関数「void sortYTypeXYHV0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYHV0()」の【仮引数】
void CopyClear::sortYTypeXYHV0(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
「TypeXYHV* pl,」は、データ配列左端「l=left省略」
「TypeXYHV* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHV」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortYTypeXYHV0()」の【アルゴリズム】
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHV0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHV0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
「TypeXYHV* p;」は、内部ポインタ(中央用)
「TypeXYHV* pi;」は、内部ポインタ(左側用)
「TypeXYHV* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHV w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHV0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHV0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHV));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHV」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y<keyY){pi++;}」で条件「pi->y<keyY」≪
詰り、左側Y座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->x<keyX){pi++;}else
if(pi->x==keyX){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->y==keyY」とY座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としX座標が同値なら、Y座標で比較し条件
「pi->x<keyX」≪詰り、左側Y座標がキーの値未満≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY<pj->y){pj--;}」で
条件「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyY==pj->y」とY座標が同値なら、X座標で比較し
条件「keyX<pj->x」≪詰り、左側X座標がキーの値越え≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
X座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYHV0(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYHV0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYHV0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYHV0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-159)関数「void sortYTypeXYHV1(
TypeXYHV* pl,TypeXYHV* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYHVでY座標 *****/
/***** 降順(Y座標→X座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortYTypeXYHV1(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHV1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHV1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYHV1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHV」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
比較は、Y座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!更にXY座標が同値の
時は、水平幅×垂直幅≪詰り、面積≫の降順≪大きい方から
小さい方へ整列≫でソートする関数です!
(B)関数「void sortYTypeXYHV1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYHV1()」の【仮引数】
void CopyClear::sortYTypeXYHV1(
TypeXYHV *pl, // データの左側Ptr
TypeXYHV *pr // データの右側Ptr
){
「TypeXYHV* pl,」は、データ配列左端「l=left省略」
「TypeXYHV* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHV」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortYTypeXYHV1()」の【アルゴリズム】
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHV1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHV1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHV *p; // 内部Ptr:中央
TypeXYHV *pi; // 内部Ptr: 左
TypeXYHV *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHV w; // 交換用の場所
「TypeXYHV* p;」は、内部ポインタ(中央用)
「TypeXYHV* pi;」は、内部ポインタ(左側用)
「TypeXYHV* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHV w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHV) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHV1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHV1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHV));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHV」と座標(X座標値Y座標値)のメン
バーとして使用するので理解し易い様にだけで無くポインタ
算出が一回でメンバー変数2個取り出すと高速化するので
中央ポインタを先ず作成してから、メンバーの座標値を取り
出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y>keyY){pi++;}」で条件「pi->y>keyY」≪
詰り、左側Y座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->y>keyY){pi++;}else
if(pi->y==keyY){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->y==keyY」とY座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としY座標が同値なら、X座標で比較し条件
「pi->x>keyX」≪詰り、左側X座標がキーの値越え≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
X座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値未満≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY>pj->y){pj--;}」で
条件「keyY>pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyY==pj->y」とY座標が同値なら、X座標で比較し
条件「keyX>pj->x」≪詰り、左側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
X座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYHV1(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYHV1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYHV1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYHV1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
★★特注「note編集機能不具合」★★
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」と
コピペでテキストを記載したら、
「keyH=p->h;keyV=p->v;keyHV=keyHkeyV;」と
等と主に「*」が消える事が多々ありますので注意して手作業
で修正して居るが、全て修正出来て無い部分が有る事に留意
して読んで頂きたい!必ず、【<>code】機能で生の
テキストを必ず参考にして下さい!!
(4-15-160)関数「void sortXTypeXYHVIX0(
TypeXYHVIX* pl,TypeXYHVIX* pr)
{・・・}」
/********************************************************************************/
/***** QUIC-SORT:座標昇順ソート:データ=TypeXYHVIXでX座標 *****/
/***** 昇順(X座標→Y座標)、降順(HV) *****/
/********************************************************************************/
void CopyClear::sortXTypeXYHVIX0(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHVIX0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHVIX0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYHVIX0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHVIX」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、X座標の大小を元に比較し、比較時にX座標が同値
ならば、Y座標の大小を比較します!更にXY座標が同値の
時は、水平幅×垂直幅≪詰り、面積≫の降順≪大きい方から
小さい方へ整列≫でソートする関数です!
「IX」は、インデックス連動する添字データを付帯してソー
ティング出来る事を示します!
(B)関数「void sortXTypeXYHVIX0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYHVIX0()」の【仮引数】
void CopyClear::sortXTypeXYHVIX0(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
「TypeXYHVIX* pl,」は、データ配列左端「l=left省略」
「TypeXYHVIX* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHVIX」≪
解説『解説クラスSuppor』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortXTypeXYHVIX0()」の【アルゴリズム】
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHVIX0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHVIX0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
「TypeXYHVIX* p;」は、内部ポインタ(中央用)
「TypeXYHVIX* pi;」は、内部ポインタ(左側用)
「TypeXYHVIX* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHVIX w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHVIX0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHVIX0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHVIX));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHVIX」と座標(X座標値Y座標値)の
メンバーとして使用するので理解し易い様にだけで無く
ポインタ算出が一回でメンバー変数2個取り出すと高速化するので中央ポインタを先ず作成してから、メンバーの座標値を取り出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x<keyX){pi++;}」で条件「pi->x<keyX」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y<keyY){pi++;}else
if(pi->y==keyY){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->x==keyX」とX座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としX座標が同値なら、Y座標で比較し条件
「pi->y<keyY」≪詰り、左側Y座標がキーの値未満≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX<pj->x){pj--;}」で
条件「keyX<pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyX==pj->x」とX座標が同値なら、Y座標で比較し
条件「keyY<pj->y」≪詰り、左側Y座標がキーの値越え≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYHVIX0(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYHVIX0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYHVIX0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYHVIX0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-161)関数「void sortXTypeXYHVIX1(
TypeXYHVIX* pl,TypeXYHVIX* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYHVIXでX座標 *****/
/***** 降順(X座標→Y座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortXTypeXYHVIX1(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHVIX1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHVIX1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortXTypeXYHVIX1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHVIX」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
ここでの座標比較は、X座標の大小を元に比較し、
比較時にX座標が同値ならば、Y座標の大小を比較します!
更にXY座標が同値の時は、水平幅×垂直幅≪詰り、面積≫
の降順≪大きい方から小さい方へ整列≫でソートする関数
です!
「IX」は、インデックス連動する添字データを付帯してソー
ティング出来る事を示します!
(B)関数「void sortXTypeXYHVIX1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortXTypeXYHVIX1()」の【仮引数】
void CopyClear::sortXTypeXYHVIX1(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
「TypeXYHVIX* pl,」は、データ配列左端「l=left省略」
「TypeXYHVIX* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHVIX」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortXTypeXYHVIX1()」の【アルゴリズム】
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHVIX1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHVIX1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
「TypeXYHVIX* p;」は、内部ポインタ(中央用)
「TypeXYHVIX* pi;」は、内部ポインタ(左側用)
「TypeXYHVIX* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHVIX w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // X座標同値なら
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // X座標同値なら
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortXTypeXYHVIX1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortXTypeXYHVIX1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHVIX));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHVIX」と座標(X座標値Y座標値)の
メンバーとして使用するので理解し易い様にだけで無く
ポインタ算出が一回でメンバー変数2個取り出すと高速化するので中央ポインタを先ず作成してから、メンバーの座標値を取り出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->x>keyX){pi++;}」で条件「pi->x>keyX」≪
詰り、左側X座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->x==keyX){if(pi->y>keyY){pi++;}else
if(pi->y==keyY){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->x==keyX」とX座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としX座標が同値なら、Y座標で比較し条件
「pi->y>keyY」≪詰り、左側Y座標がキーの値越え≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値未満≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyX>pj->x){pj--;}」で
条件「keyX>pj->x」≪詰り、右側X座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyX==pj->x」とX座標が同値なら、Y座標で比較し
条件「keyY>pj->y」≪詰り、左側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortXTypeXYHVIX1(pl,pj);}」
で再帰呼び出しを自分自身「sortXTypeXYHVIX1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortXTypeXYHVIX1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortXTypeXYHVIX1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-162)関数「void sortYTypeXYHVIX0(
TypeXYHVIX* pl,TypeXYHVIX* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:昇順ソート:データ=TypeXYHVIXでY座標 *****/
/***** 昇順(Y座標→X座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortYTypeXYHVIX0(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHVIX0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHVIX0( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYHVIX0();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHVIX」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「0」は、データ配列を昇順≪小さい方から大きい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を昇順≪小さい方
から大きい方へ整列≫にソートする関数です!ここでの座標
比較は、Y座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!更にXY座標が同値の
時は、水平幅×垂直幅≪詰り、面積≫の降順≪大きい方から
小さい方へ整列≫でソートする関数です!
「IX」は、インデックス連動する添字データを付帯してソー
ティング出来る事を示します!
(B)関数「void sortYTypeXYHVIX0();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYHVIX0()」の【仮引数】
void CopyClear::sortYTypeXYHVIX0(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
「TypeXYHVIX* pl,」は、データ配列左端「l=left省略」
「TypeXYHVIX* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHVIX」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortYTypeXYHVIX0()」の【アルゴリズム】
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHVIX0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHVIX0( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
「TypeXYHVIX* p;」は、内部ポインタ(中央用)
「TypeXYHVIX* pi;」は、内部ポインタ(左側用)
「TypeXYHVIX* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHVIX w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y < keyY ){ // 左側が小さい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x < keyX ){ // 左側が小さい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY < pj->y ){ // 右側が大きい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX < pj->x ){ // 右側が大きい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHVIX0( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHVIX0( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHVIX));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHVIX」と座標(X座標値Y座標値)の
メンバーとして使用するので理解し易い様にだけで無く
ポインタ算出が一回でメンバー変数2個取り出すと高速化するので中央ポインタを先ず作成してから、メンバーの座標値を取り出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタの
メンバー変数として取り出すのでポインタ使用が高速化に
寄与している事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y<keyY){pi++;}」で条件「pi->y<keyY」≪
詰り、左側Y座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->x<keyX){pi++;}else
if(pi->x==keyX){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->y==keyY」とY座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としX座標が同値なら、Y座標で比較し条件
「pi->x<keyX」≪詰り、左側Y座標がキーの値未満≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
Y座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY<pj->y){pj--;}」で
条件「keyY<pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyY==pj->y」とY座標が同値なら、X座標で比較し
条件「keyX<pj->x」≪詰り、左側X座標がキーの値越え≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
X座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;*pi=*pj;*pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYHVIX0(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYHVIX0()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYHVIX0(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYHVIX0(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
(4-15-163)関数「void sortYTypeXYHVIX1(
TypeXYHVIX* pl,TypeXYHVIX* pr){・・・}」
/****************************************************************************/
/***** QUIC-SORT:降順ソート:データ=TypeXYHVIXでY座標 *****/
/***** 降順(Y座標→X座標)、降順(HV) *****/
/****************************************************************************/
void CopyClear::sortYTypeXYHVIX1(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHVIX1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHVIX1( pi, pr ); // この間をソート
} //
}
☆備考☆この関数はファイル「CopyClear100.cpp」に存在!
★注意★この関数は「private:属性」ですのでライブラリの
外から使用不能です!
(A)関数「sortYTypeXYHVIX1();」の【関数名】
「Sort」は、勿論、英単語「sort」、カタカナ語ソート・
ソーティング、詰り並び替えです!
★注意★構造体「TypeXYHVIX」は、XY座標関連です!
このデータは、XY座標の値でソーティングします!
「1」は、データ配列を降順≪大きい方から小さい方へ整列
≫にソートする関数を意味!
この関数は、XY座標の値でデータ配列を降順≪大きい方
から小さい方へ整列≫にソートする関数です!
比較は、Y座標の大小を元に比較し、比較時にY座標が同値
ならば、X座標の大小を比較します!更にXY座標が同値の
時は、水平幅×垂直幅≪詰り、面積≫の降順≪大きい方から
小さい方へ整列≫でソートする関数です!
「IX」は、インデックス連動する添字データを付帯してソー
ティング出来る事を示します!
(B)関数「void sortYTypeXYHVIX1();」の【返値】
返値を返さない関数です!
★注意★詰り、実引数の検査を実行時に行いませんので
使用する時は、正しい実引数を記載する必要が有ります!
(C)関数「sortYTypeXYHVIX1()」の【仮引数】
void CopyClear::sortYTypeXYHVIX1(
TypeXYHVIX *pl, // データの左側Ptr
TypeXYHVIX *pr // データの右側Ptr
){
「TypeXYHVIX* pl,」は、データ配列左端「l=left省略」
「TypeXYHVIX* pr」は、データ配列右端「r=right省略」
ここで使用する専用の型「TypeXYHVIX」≪
解説『解説クラスSupport』の(2-3)
座標矩形範囲用データ構造で解説≫
(D)関数「sortYTypeXYHVIX1()」の【アルゴリズム】
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHVIX1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHVIX1( pi, pr ); // この間をソート
} //
}
(D-1)ローカル変数
){
TypeXYHVIX *p; // 内部Ptr:中央
TypeXYHVIX *pi; // 内部Ptr: 左
TypeXYHVIX *pj; // 内部Ptr: 右
int keyX; // 中央の値:X
int keyY; // 中央の値:Y
int keyH; // 中央の値:H
int keyV; // 中央の値:V
int keyHV; // 中央の値:H×V
TypeXYHVIX w; // 交換用の場所
「TypeXYHVIX* p;」は、内部ポインタ(中央用)
「TypeXYHVIX* pi;」は、内部ポインタ(左側用)
「TypeXYHVIX* pj;」は、内部ポインタ(右側用)
「int keyX;」は、中央の値(キー比較用のX座標)
「int keyY;」は、中央の値(キー比較用のY座標)
「int keyH;」は、中央の値(キー比較用の水平幅)
「int keyV;」は、中央の値(キー比較用の垂直幅)
「int keyHV;」は、中央の値(キー比較用の面積)
「TypeXYHVIX w;」は、データ交換用の場所
(D―2)アルゴリズムコード
pi = pl; // KeyDataの左側Set
pj = pr; // KeyDataの右側Set
p = pi + ( (int)pj - (int)pi ) // 右左の中央値を
/ ( 2 * sizeof(TypeXYHVIX) ); // セット
keyX = p->x; // X座標を取り出す
keyY = p->y; // Y座標を取り出す
keyH = p->h; // 水平幅を取り出す
keyV = p->v; // 垂直幅を取り出す
keyHV = keyH * keyV; // 中央の値:H×V算出
do{ // 以下繰り返し
for(;;){ // 以下繰り返し:内側
if( pi->y > keyY ){ // 左側が大きい間:Y
pi++; // 左側を中に進める
}else if( pi->y == keyY ){ // Y座標同値なら
if( pi->x > keyX ){ // 左側が大きい間:X
pi++; // 左側を中に進める
}else if( pi->x == keyX ){ // XY座標同値なら
if( pi->h * pi->v > keyHV ){ // 左側が大きい間:HV降順
pi++; // 左側を中に進める
}else{ // 小さい場合:HV
break; // 内側Loop終了
} //
}else{ // 小さい場合:X
break; // 内側Loop終了
} //
}else{ // 小さい場合:Y
break; // 内側Loop終了
} //
} //
for(;;){ // 以下繰り返し:内側
if( keyY > pj->y ){ // 右側が小さい間:Y
pj--; // 右側を中に進める
}else if( keyY == pj->y ){ // Y座標同値なら
if( keyX > pj->x ){ // 右側が小さい間:X
pj--; // 右側を中に進める
}else if( keyX == pj->x ){ // XY座標同値なら
if( keyHV > pj->h * pj->v ){ // 右側が小さい間:HV降順
pj--; // 右側を中に進める
}else{ // 大きい場合:HV
break; // 内側Loop終了
} //
}else{ // 大きい場合:X
break; // 内側Loop終了
} //
}else{ // 大きい場合:Y
break; // 内側Loop終了
} //
} //
if( pi <= pj ){ // 左 ≦ 右 なら
w = *pi; // 左右のキーデータ
*pi = *pj; // を交換
*pj = w; // し
pi++; // 左側を中に進める
pj--; // 右側を中に進める
} //
}while( pi <= pj ); // 左≦右なら繰返し
if( pl < pj ){ // 外左 < 中右 なら
sortYTypeXYHVIX1( pl, pj ); // この間をソート
} //
if( pi < pr ){ // 中左 < 外右 なら
sortYTypeXYHVIX1( pi, pr ); // この間をソート
} //
}
「pi=pl;pj=pr;」は、ローカルな左側・右側をセット
「p=pi+((int)pj-(int)pi)/(2*sizeof(TypeXYHVIX));」は、
ローカルなデータ配列の中央へのポインタをセット
「keyX=p->x;keyY=p->y;」は、左右の中央の場所の
キー値「p->x」とX座標、「p->y」とY座標、と今回は、
詰りXY座標値を取り出す!★備考★他の関数では中央値
へのポインタを算出せずに直接、キーデータを取り出して
居ますが、「TypeXYHVIX」と座標(X座標値Y座標値)の
メンバーとして使用するので理解し易い様にだけで無くポインタ算出が一回でメンバー変数2個取り出すと高速化するので中央ポインタを先ず作成してから、メンバーの座標値を取り出す事にしました!
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」は、キーデータとして水平幅・垂直幅を取り出し★備考★ポインタのメン
バー変数として取り出すのでポインタ使用が高速化に寄与し
ている事に留意★面積キーデータ作成!
二重ループで外側の
do構文「・・外側ループ本体・・}while(pi<=pj);」と
後置ループ条件「pi<=pj」と内部のポインタの左右関係が
保たれている間繰り返す!そして最初の内側のループ
「for(;;){・・無限ループ本体・・}」は、for無限ルー
プ構文「for(;;)」で無限ループ本体で「break;」でループ
から脱出する事でループを構築するが、無限ループ本体は、
先ず、「if(pi->y>keyY){pi++;}」で条件「pi->y>keyY」≪
詰り、左側Y座標がキーの値未満≫の間「pi++;」ポインタ
を右側に移動を繰り返す、次に
「else if(pi->y==keyY){if(pi->y>keyY){pi++;}else
if(pi->y==keyY){if(pi->hpi->v>keyHV){pi++;}
else{break;}}else{break;}}else{break;}}」
と条件「pi->y==keyY」とY座標が同値の時、★備考★
前述の関数「sortYTypeXYD1()アルゴリズム説明では、長々
と日本語で解説を説明して居ましたが、今回は「X座標・
Y座標・面積」と3パターン比較する項目があり、if構文
の組み合わせも複雑に成り、寧ろnote「<>コード」
機能で示したソースコード直にインデント(字下げ)で
グラフィカルに構造は直接確認された方がC言語に馴れて居
る方で無くとも分かり易いと思い解説する方針を変えます★
上記「else if(・・複雑なif構文組み合わせ・・}}」は、
数値大小比較としY座標が同値なら、X座標で比較し条件
「pi->x>keyX」≪詰り、左側X座標がキーの値越え≫の
間「pi++;」ポインタを右側に移動を繰り返す、そして
X座標も同値なら、面積で比較し条件
「pi->hpi->v>keyHV」≪詰り、左側面積がキーの値未満≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
次の内側ループも「for(;;){・・無限ループ本体・・}」
は、for無限ループ構文「for(;;)」で無限ループ本体で
「break;」でループから脱出する事でループを構築するが、
無限ループ本体は、先ず、「if(keyY>pj->y){pj--;}」で
条件「keyY>pj->y」≪詰り、右側Y座標がキーの値未満≫
の間「pj--;」ポインタを左側に移動を繰り返す、次に
「if(keyY<pj->y){pj--;}else if(keyY==pj->y){
if(keyX<pj->x){pj--;}else if(keyX==pj->x){
if(keyHV>pj->hpj->v){pj--;}else{break;}}else{
break;}}else{break;}」と
条件「keyY==pj->y」とY座標が同値なら、X座標で比較し
条件「keyX>pj->x」≪詰り、左側Y座標がキーの値未満≫の
間「pj--;」ポインタを左側に移動を繰り返す、そして
X座標も同値なら、面積で比較し条件
「pi->h*pi->v>keyHV」≪詰り、左側面積がキーの値越え≫
の間「pi++;」ポインタを右側に移動を繰り返す!
とシンプルな日本語表現で解説しました!
そしてif構文
「if(pi<=pj){w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」は、
条件「pi<=pj」と左右関係が保たれていたら
「w=*pi;*pi=*pj;*pj=w;pi++;pj--;}」で先ず
「w=*pi;pi=pj;pj=w;」でキーデータ左右を入れ替え、
「pi++;pj--;」とローカル左右ポインタを進める!
「do構文」を終えると!
そして「if(pl<pj){sortYTypeXYHVIX1(pl,pj);}」
で再帰呼び出しを自分自身「sortYTypeXYHVIX1()」関数を
サブルーチン関数として条件「pl<pj」=「元々の左側が
内部の右側と左右関係が保たれて居る」なら、再帰呼び出し
「sortYTypeXYHVIX1(pl,pj);」を行う事で数学の
「帰納的定義法」と考えて再帰呼び出しを行った部分
「plからpjのポインタの示す左右範囲」が昇順にソート済
みと見なして処理する方法です!★備考★これが再帰呼び出
しを行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムです同じ様に
「if(pi<pr){sortYTypeXYHVIX1(pi,pr);}」で範囲
「piからpr」のポインタの示す左右範囲」が昇順にソート
済みと見なして処理します!★備考★これが、再帰呼び出し
を行う事で実現する「クイックソート」と呼ばれる通常の
データでは最速と言われているアルゴリズムですコレは、
多くの画像処理以外のプログラミングで使用されて居ますの
で数学的帰納法をアルゴリズムに応用した事を理解して下さ
い!C言語的には「再帰呼び出し」との文言で平気で多用し
ます!
★★特注「note編集機能不具合」★★
「keyH=p->h;keyV=p->v;keyHV=keyH*keyV;」と
コピペでテキストを記載したら、
「keyH=p->h;keyV=p->v;keyHV=keyHkeyV;」と
等と主に「*」が消える事が多々ありますので注意して手作業
で修正して居るが、全て修正出来て無い部分が有る事に留意
して読んで頂きたい!必ず、【<>code】機能で生の
テキストを必ず参考にして下さい!!
ココまでで区切り≪「private:属性」の関数の並びが、
「sortYTypeXYHVIX1()」関数までとソート系「XY座標」が
終了したので次から「sortAreaTypeSf0()」とソート系
「面積」関数の説明になるので≫が良いので終わります?!
継続追加は有りません!★備考★
勿論、記載ミスは直して行きますが!
引き続き、
新規解説『解説クラスCopyClear(38)』を
御贔屓下さい!