【Cベースのソートアルゴリズム】挿入ソートのヒルソート

序文

この記事は、著者の学習経験とソート アルゴリズムの挿入ソートにおけるヒル ソートの経験を共有するために C 言語に基づいています。レベルが限られているため、間違いは避けられません。修正や交換を歓迎します。

ヒルソート

ヒル ソート法は、縮小増分法としても知られています。Hill ソート法の基本的な考え方は次のとおりです。まず、ソート対象のレコードのシーケンス全体を直接挿入ソートのためにいくつかのサブシーケンスに分割し、シーケンス全体のレコードが「基本的に順序付けされている」場合に、直接挿入ソートを実行します。すべてのレコードを順に表示します。

ヒル ソートは、挿入ソートの次の 2 つの特性に基づいて改良された方法です。

  • 挿入ソートは、ほぼソートされたデータを操作する場合に効率的です。つまり、線形ソートの効率を達成できます。
  • ただし、挿入ソートは一度に 1 ビットしかデータを移動できないため、一般に非効率的です。

なぜ縮小増分法とも呼ばれるのでしょうか? 直接挿入ソートを見てみましょう。比較するたびに要素は 1 つずつ移動しますか? 実際、直接挿入による並べ替えのデフォルトの増分 (ギャップで表される) は 1 で、つまり、1 つおきの要素が比較されます。ヒルソートとは、最初に設定した増分値から配列に対して直接挿入ソートを行い、ソートが完了するたびに増分ギャップを減らしていき、最後は1ずつ増分した直接挿入ソートとなります。

手順:

  1. 事前ソートの目的: 順序を近い順序に保つこと

    ギャップ間隔のあるデータを 1 つのグループに分割し、合計でギャップ グループが存在し、各ラウンドで各グループのデータを直接挿入してソートし、ラウンドごとにギャップを減らします。

  2. 直接挿入ソート

    ギャップが 1 に減少すると、最後の直接挿入ソートが実行されます。

次の例に従ってプロセスを説明します (昇順が必要です)。

最初にギャップを 3 として選択し、図に示すようにグループができました。異なる色の数字は異なるグループを表します。実際、各グループのソートは、直接挿入ソートの改良版と同等です。ギャップの値を 1 から Got 3 に変更します。

画像-20220813174425646

int gap = 3;
//单轮排序
for(int j = 0; j < gap; ++j)
{
    
    
    //单组排序
    for(int i = 0; i < n - gap; i += gap)
    {
    
    
        int end = i;
        int tmp = arr[end + gap];
        while(end >= 0)
        {
    
    
            if(tmp < arr[end])
            {
    
    
                arr[end + gap] = arr[end];
            }
            else
                break;
            end -= gap;
        }
        arr[end + gap] = tmp;        
    } 
}

画像-20220813175102900

画像-20220813175329119

ここでギャップの初期値を取得し、最終的にギャップが 1 になるようにsz / 3毎回 1 を加算します。gap = gap / 3 + 1assert は arr ポインタが空かどうかを検出するもので、通常の状況では空であることは不可能です。

void ShellSort(int* arr, int sz)
{
    
    
    assert(arr);
    
    int gap = sz;
    while(gap > 1)
    {
    
    
        gap = gap / 3 + 1;
        //单轮排序
        for(int j = 0; j < gap; ++j)
        {
    
    
            //单组排序
            for(int i = j; i < n - gap; i += gap)
            {
    
    
                int end = i;
                int tmp = arr[end + gap];
                while(end >= 0)
                {
    
    
                    if(tmp < arr[end])
                        arr[end + gap] = arr[end];
                    else
                        break;
                    end -= gap;
                }
                arr[end + gap] = tmp;        
            }        
        }        
    }
    
}

このように実装すると、コードがちょっと...ハッタリっぽく見えることがわかりました。一見すると、4 つのループのセットではありませんか? これはグループで行われますが、コードをより「快適」に見せる方法はありますか?

ギャップグループのデータを複数のグループで並べて実行できますが、これは何を意味しますか? 次の図を例に挙げます。毎回 1 ステップだけ後退し、赤グループのデータに遭遇した場合は赤グループの直接挿入ソートを実行し、青グループのデータに遭遇した場合は青グループを実行します。黒人グループは黒人グループをやります。終了するたびに一巡の仕分けです。

画像-20220813174425646

void ShellSort(int* arr, int sz)
{
    
    
    assert(arr);
    
    int gap = sz;
    while(gap > 1)
    {
    
    
        gap = gap / 3 + 1;
        //单轮排序
        for(int i = 0; i < n - gap; ++i)
        {
    
    
            int end = i;
            int tmp = arr[end + gap];
            while(end >= 0)
            {
    
    
                if(tmp < arr[end])
                    arr[end + gap] = arr[end];
                else
                    break;
                end -= gap;
            }       
        }     
    }

}

私たちが見つけたのは

ギャップが大きいほど、大きなデータはより速く後方にジャンプでき、小さなデータはより速く前にジャンプできます (たとえば、ギャップが 3 の場合、一度に 3 つの要素位置にまたがって並べ替えることができ、ギャップが 1 の場合、かなり遅くなります)。

ギャップが小さいほど、ジャンプは遅くなり (たとえば、ギャップが 1 の場合、一度に 1 つの要素のみを並べ替えることができます)、順序に近づきます。

:

  • ギャップ>1は事前ソートです

  • ギャップ == 1 は直接挿入ソートです

  • 最後のギャップが 1 であることを確認する必要があり、ギャップの値には多くのオプションがありますが、ここではgap = sz / 2sumgap /= 2またはgap = sz / 3 sumをお勧めしますgap = gap / 3 + 1

ヒルソートの特徴の概要:

  1. ヒル ソートは直接挿入ソートを最適化したものです。
  2. ギャップ > 1 の場合、事前に並べ替えられます。目的は、配列を順序に近づけることです。ギャップ == 1 の場合、配列はすでに順序に近いため、
    非常に高速になります。これにより、全体の最適化効果が得られる。実装した後は、パフォーマンス テストを比較できます。
  3. ヒル ソートの時間計算量を計算するのは簡単ではありません。ギャップを評価する方法が多数あり、それが計算を困難にするためです。そのため、多くの書籍で示されている
    ヒル ソートの時間計算量は固定されていません。

画像-20220813102430656

画像-20220813102436571

私たちのギャップは Knuth によって提案された方法に従って評価されており、Knuth は多数の実験統計を行っているため、次に従って一時的に計算します: O(n 1.25 ) から O(1.6n 1.25 )、効率O ( nlogn ) 同様に、データ量が多い場合は O(nlogn) よりも若干悪くなります。いずれの場合でも、ヒル ソートは時間計算量でO(n 2 ) を突破します。

  1. 安定性: 不安定

ご覧いただきありがとうございます、あなたのサポートが私の最大の励みです〜

おすすめ

転載: blog.csdn.net/weixin_61561736/article/details/126796564