データ構造とアルゴリズムの基礎 (Wang Zhuo) (33): バイナリ挿入ソート、ヒル ソート

目次

バイナリ挿入ソート

 プロジェクト 1:

問題: 要素を挿入する前に要素を移動する操作がありません

プロジェクト 2: (最終製品、結果)

ヒルソート

 プロジェクト 1:(個人的なアイデア)

標準回答: (PPT 回答)

解説:(実際にプログラムを実行する際のアルゴリズムの論理順序は、王卓氏がオンライン授業で教えたものとは実際には異なります)

(1): アサイン段階

(2):1回戦【初回】比較

 (3):2回戦から(d)ラウンドまでの比較【1回目】

(4):1ラウンド目から(d)ラウンドまでの比較[2ラウンド目以降]

ここからがポイントです。

連続して比較するときに異なる間隔サイズ d を調整する方法については、ここでの標準的な回答で示されている方法は次のとおりです。

慈悲深い答え:

ローカリゼーション


バイナリ挿入ソート


実際の例とスケッチに基づいて、次のプログラムを直接作成します。 

 プロジェクト 1:

void BinsertSort(SqList& L)
{
    int i ,low = 1, high = i - 1;
    for (i = 1; i < L.length; i++)
    {
        if (L.r[i].key < L.r[i - 1].key)
            L.r[0] = L.r[i];
        //if可以放到最高优先级
        for (int mid = (low + high) / 2; high > low; mid = (low + high) / 2)
        {
            if (L.r[0].key < L.r[mid].key)
                high = mid - 1;
            else //if (L.r[0].key > L.r[mid].key)
                low = mid + 1;
        }
        L.r[high + 1].key = L.r[0].key;
        //L.r[low - 1].key = L.r[0].key;
    }
}

バイナリ挿入;
バイナリ: バイナリ; 2 つの数値のみに基づく; バイナリ; 2 つの部分からなる;

問題: 要素を挿入する前に要素を移動する操作がありません


プロジェクト 2: (最終製品、結果)

void BinsertSort(SqList& L)
//binary insert;
//binary:二进制的; 仅基于两个数字的; 二元的; 由两部分组成的;
{
    int i;
    for (i = 1; i < L.length; i++)
        //i表示位序
    {
        if (L.r[i].key < L.r[i - 1].key)
            L.r[0] = L.r[i];
int low = 1, high = i - 1;
        for (int mid = (low + high) / 2; high > low; mid = (low + high) / 2)
        {
            if (L.r[0].key < L.r[mid].key)
                high = mid - 1;
            else //if (L.r[0].key > L.r[mid].key)
                low = mid + 1;
        }
        for (int j = i; j >= high + 1; j--)
            L.r[j + 1].key = L.r[j].key;

        L.r[high + 1].key = L.r[0].key;
        //L.r[low - 1].key = L.r[0].key;
    }
}

ヒルソート

実際の例とスケッチに基づいて、次のプログラムを直接作成します。 

 プロジェクト 1:(個人的なアイデア)

void ShellSort(SqList& L) 
{
    for (int i = 0; i <= L.length / 5; i++)
    {
        for (int i = 0; i <= L.length; i += 5)
        {
            每次都把数据存储到中序二叉树,再用中序遍历把这些元素全部都重新插回去
        }
        递归...
    }
}

標準回答: (PPT 回答)

void ShellInsert(SqList& L, int d)
//distance:每次一步往后跨多远(5,3,1...)
{
    int i, j;
    for (i = d + 1; i < L.length; i++) 
    {
        if (L.r[i].key < L.r[i - d].key) 
            //比较的诸多元素里,第二个元素大于第一个元素
        {
            L.r[0] = L.r[i];  
            for (j = i - d; //第一个元素
                j > 0 && (L.r[0].key < L.r[j].key);
                j -= d)
                L.r[j + d] = L.r[j];  //记录后移
            L.r[j + d] = L.r[0];  
        }
    }
}
void ShellSort(SqList& L, int dlta[], int t)
//t:循环总共趟数
{
    for (int k = 0; k < t; k++)
        ShellInsert(L, dlta[k]); 
    //dlta[k]:增量(5, 3, 1...)
}

解説:(実際にプログラムを実行する際のアルゴリズムの論理順序は、王卓氏がオンライン授業で教えたものとは実際には異なります)


(1): アサイン段階

i の初期値は、各比較の 2 番目の要素です。

比較した多数の要素のうち、2 番目の要素が最初の要素より大きい場合: ループを開始します


(2):1回戦【初回】比較

最初の比較ラウンドの最初の操作では、以前に選択した 2 つの要素のみが比較されます。


1番目と(d+1)番目の要素を比較します

  1. 2 番目の要素をセンチネルに入れます
  2. 最初の要素が 2 番目の要素をカバーします
  3. 次に、2 番目の要素をセンチネルから最初の要素の位置に転送します。

次に: j-=d; => j<0


第一回目の比較が終わりました

実際、このブロックの完全な並べ替えはまだ終わっていません

ただし、ヒルソートは教師が教えたアルゴリズムのアイデアから逸脱しているため、

したがって、データを d 個の部分に分割し、アルゴリズムの最初のラウンドで合計 d ラウンドの並べ替えを実行すると、ここで一時停止して終了します。


その後 (最初の比較の後で)、私たちが実行した操作は王氏が言ったとおりではありませんでした。

次のブロックに移動してフィルタリングし、3 番目以降の他の要素を比較および並べ替えます。

代わりに、ブロック アルゴリズムの操作を一時的に中断し、データ内に保存した 2 番目の要素を見つけます。


 (3):2回戦から(d)ラウンドまでの比較【1回目】

比較:

2 番目と (d+2) 番目、3 番目と (d+3) 番目、4 番目と (d+4) 番目...

(d)回目との比較まで:d回目と(d*2)回目

これで、ソートされた要素の最初の 2D シーケンスがすでにできています。

最初の d 要素 (k: ビット順序)

それぞれ未満

次の (d+k) ビット要素


(4):1ラウンド目から(d)ラウンドまでの比較[2ラウンド目以降]

(2) および (3) の比較手順と同様に、後続のすべての要素が比較されるまで比較を続けます。

 ただし、この場所内 (ステップ 4):

各比較後 [定義した順序ルールによって区別されます (グループとしての d ごと)]

内部の最後の 2 つの要素の後

(2)、(3) のステップを超える操作も実行します。

各グループのシーケンスの前にあるすべての要素を再トラバースします。

つまり、次のようになります。

各キュー シーケンスの最後の 2 つの要素を比較した後、前方に 1 つずつ比較を続けます。

比較において後の要素が前の要素より小さい場合、後の要素を前に置きます。


ここからがポイントです。

合計 2 つを超えるデータ範囲が比較された後、各比較の各ラウンドで次のようになります。

[比較後の小さい要素] と [前のシーケンスの要素] の比較を続けます。

i が指す要素から開始して、シーケンス全体の前にあるすべての要素を比較します。


このプロセスでは、「並べ替え」操作の全体/すべてのプロセス (プロセス) が完了しました。

一つ一つ比較する

小さい要素を前位置に変更(小さい要素を前に移動)

大きな要素が後ろの位置に交換されます(大きな要素に遭遇した場合は後ろに移動します)

 3 つ以上のデータ範囲を比較した後、要素が比較されるたびに

前のすべての要素を比較する (横断する) 操作は非常に簡単で、プログラムの各比較のサイクルに文を追加します。

このシーケンスの前の要素がすべて比較されるまで、前の要素との比較を続けます。

これは次のように行われます。

            for (j = i - d; //第一个元素
                j > 0 && (L.r[0].key < L.r[j].key);
                j -= d)

このプログラムによって実行される for ステートメント設計コード

これは、アルゴリズムプログラムの動作プロセス全体のフレーム構築の核心であり、繊細さ です。


連続して比較するときに異なる間隔サイズ d を調整する方法については、ここでの標準的な回答で示されている方法は次のとおりです。

毎回、特定のルール dlta[]

(機能?それとも何???彼はここで毎回対応する関係を示していませんでした。私は彼が何をしているのかさえ知りません) いくつかの定期的な変更を加えます。

    for (int k = 0; k < t; k++)//t:循环总共趟数
        ShellInsert(L, dlta[k]); 

私はここで彼に少し混乱しています、そして私は彼が何をしているのか分かりません


彼の書いた制御方法はクソの山だと思うので、すべてのデータを毎回 2 つに分割する操作の例を見てみましょう。

慈悲深い答え:

//希尔排序
void ShellSort(int A[], int n)
{
    int d, i, j;
    //A[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已到
    for (d = n / 2; d >= 1; d = d / 2)
        //步长变化
        for (i = d + 1; i <= n; ++i)
            if (A[i] < A[i - d])
                //需将A[i]插入有序增量子表
            {
                A[0] = A[i];
                //暂存在A[0]
                for (j = i - d; j > 0 && A[0] < A[j]; j -= d)
                    A[j + d] = A[j];
                //记录后移,查找插入的位置
                A[j + d] = A[0];
            }//if
}

設定した前提条件に従って、必要に応じて変更します: (プログラムをローカライズします)

ローカリゼーション:

void ShellSort(SqList& L)
{
    int  i, j;
    for (int d = L.length / 2; d >= 1; d = d / 2)
        //步长变化

        for (i = d + 1; i <= L.length; ++i)
            if (L.r[i].key < L.r[i - d].key)
            {
                L.r[0] = L.r[i];
                for (j = i - d; j > 0 && L.r[0].key < L.r[j].key; j -= d)
                    L.r[j + d] = L.r[j];
                L.r[j + d] = L.r[0];
            }//if
}

この観点から、実際には (実際には)、各連続比較の補償 d を制御するために使用されるプログラムには、次の段落だけが必要です。

    for (int d = L.length / 2; d >= 1; d = d / 2)

おすすめ

転載: blog.csdn.net/Zz_zzzzzzz__/article/details/130310206