データ構造とアルゴリズム(Golang実装)(22)ソートアルゴリズム-ヒルソート

ヒルソート

1959年に、Donald L. Shell (March 1, 1924 – November 2, 2015)アメリカ人という名前Communications of the ACM 国际计算机学会月刊の並べ替えアルゴリズムがリリースされ、ヒル並べ替えという名前のアルゴリズムが誕生しました。

注:ACM = Association for Computing Machinery1947年に設立された、コンピュータ実践者のための世界的な専門組織であるInternational Computer Societyは、世界で最初の科学的および教育的コンピュータ社会です。

ヒルソートは直接挿入ソートの改良版です。直接挿入ソートは、ほとんどソート済みのシーケンスに対して非常に効率的であるため、O(n)線形の複雑さを実現しますが、一度に1ビットしかデータを移動できません。Hillのクリエイティブソートでは、データをn少しシフトすることができ、その後、n常に直接挿入ソートと同じに削減されます1。次の分析を参照してください。

ヒルソートは挿入ソートアルゴリズムです。

1.アルゴリズムの紹介

N一連の数字があります:

  1. 最初により小さいN整数を取り、d1位置がd1整数の倍数である数値を1つのグループにまとめ、これらの数値を直接挿入して並べ替えます。
  2. 次に、より小さいd1整数を取り、d2位置がd2整数の倍数である数値を1つのグループにまとめ、数値を直接挿入して並べ替えます。
  3. 次に、より小さいd2整数を取り、d3位置がd3整数の倍数である数値を1つのグループにまとめ、数値を直接挿入して並べ替えます。
  4. ...
  5. integerが得られるまでd=1、直接挿入ソートを使用します。

これはグループ化挿入方法です。最後の反復は直接挿入ソートに相当し、他の反復はn直接挿入ソート距離を移動するたびに相当します。これらの整数は2つの数値間の距離です。

シーケンスの長さの半分を増分として受け取り、増分が1になるまで毎回半分にします。

簡単な例として、Hillは12個の要素のシーケンスを並べ替え[5 9 1 6 8 14 6 49 25 4 6 3]ます。インクリメントd値は次のとおりです6,3,1::

x 表示不需要排序的数


取 d = 6 对 [5 x x x x x 6 x x x x x] 进行直接插入排序,没有变化。
取 d = 3 对 [5 x x 6 x x 6 x x 4 x x] 进行直接插入排序,排完序后:[4 x x 5 x x 6 x x 6 x x]。
取 d = 1 对 [4 9 1 5 8 14 6 49 25 6 6 3] 进行直接插入排序,因为 d=1 完全就是直接插入排序了。

シーケンスの順序付けが多いほど、直接挿入ソートの効率が高くなります。ヒルソートは、グループ化による直接挿入ソートを使用します。ステップサイズが1大きいため、順序付けられていないシーケンスを最初は無秩序に少なく変更できます。交換の数も減り、1直接挿入ソートの最後のステップが使用されるまで、シーケンスはすでに比較的順序付けられているので、時間の複雑さが少し良くなります。

最良の場合、つまりシーケンスが順序付けられている場合、logn各直接挿入ソートの最適な時間の複雑さは次のとおりであるO(n)ため、ヒルソートはサブインクリメンタル直接挿入ソートを実行する必要があります。したがって、ヒルソートに最適な時間複雑:O(nlogn)

最悪の場合、増分シーケンスが次のとおりであると想定して、各反復は最悪です。d8 d7 d6 ... d3 d2 1次に、直接挿入されるソート要素の数は次のとおりです。n/d8 n/d7 n/d6 .... n/d3 n/d2 n次に、時間の複雑さが直接挿入の最悪の複雑さとして計算されます。 :

假设增量序列为 ⌊N/2⌋ ,每次增量取值为比上一次的一半小的最大整数。

O( (n/d8)^2 + (n/d7)^2 + (n/d6)^2 + ... + (n/d2)^2 + n^2)

= O(1/d8^2 + 1/d7^2 + 1/d6^2 + ... + 1/d2^2 + 1) * O(n^2)
= O(等比为1/2的数列和) * O(n^2)
= O(等比求和公式) * O(n^2)
= O( (1-(1/2)^n)/(1-1/2) ) * O(n^2)
= O( (1-(1/2)^n)*2 ) * O(n^2)
= O( 2-2*(1/2)^n ) * O(n^2)
= O( < 2 ) * O(n^2)

したがって、ヒルソートの最悪の時間の複雑さはO(n^2)です。

グループ化の増分シーケンスが異なると、時間の複雑さが異なりますが、どのシーケンスが最適であるかを証明することはできません。Hibbardインクリメンタルシーケンス:1,3,7,···,2n−1パケットの順序が広く証明することができ、時間の複雑さは、次のとおりですΘ(n^1.5)

ヒルのソートの時間の複雑さはこの範囲O(n^1.3)~O(n^2)にあります。数学で厳密に証明することは不可能です。

グループ化の各ラウンドは直接挿入ソートを使用するため、ヒルソートは安定していませんが、グループ化はn位置にまたがるため、2つの同一の番号が発生し、相手が見つからない場合、順序の変更は見つかりません。

2.アルゴリズムの実装

package main

import "fmt"

// 增量序列折半的希尔排序
func ShellSort(list []int) {
    // 数组长度
    n := len(list)

    // 每次减半,直到步长为 1
    for step := n / 2; step >= 1; step /= 2 {
        // 开始插入排序,每一轮的步长为 step
        for i := step; i < n; i += step {
            for j := i - step; j >= 0; j -= step {
                // 满足插入那么交换元素
                if list[j+step] < list[j] {
                    list[j], list[j+step] = list[j+step], list[j]
                    continue
                }
                break
            }
        }
    }
}

func main() {
    list := []int{5}
    ShellSort(list)
    fmt.Println(list)

    list1 := []int{5, 9}
    ShellSort(list1)
    fmt.Println(list1)

    list2 := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3}
    ShellSort(list2)
    fmt.Println(list2)

    list3 := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3, 2, 4, 23, 467, 85, 23, 567, 335, 677, 33, 56, 2, 5, 33, 6, 8, 3}
    ShellSort(list3)
    fmt.Println(list3)
}

出力:

[5]
[5 9]
[1 3 4 5 6 6 6 8 9 14 25 49]
[1 2 2 3 3 4 4 5 5 6 6 6 6 8 8 9 14 23 23 25 33 33 49 56 85 335 467 567 677]

以前に分析されたいくつかのソートアルゴリズムによると、ソートされる配列が小規模の場合、直接挿入ソートを使用することが一般的に推奨されます。ヒルソートは中規模の場合に使用できますが、大規模でも迅速なソート、マージソート、またはヒープが必要です。並べ替え。

シリーズ記事エントリー

私は、スター陳思い、私が個人的に書かれているようこそ(Golangが達成)のデータ構造とアルゴリズムの記事で始まる、より親しみやすいGitBookを読むために

おすすめ

転載: www.cnblogs.com/nima/p/12724858.html