序文:インターネットで多くの説明を読んだ後、直感的には感じられない。そのため、私は、Hillアルゴリズムを明確に説明するために自国語を使用する予定です。挿入ソートの改良版であることは誰もが知っています。一連のデータにローカルで順序付けされた数値がある場合、挿入ソートがより効率的であることは誰もが知っています。(理解できない場合は、理解に行くことができます)。この機能を知って、Hillアルゴリズムはこれから生まれました。
まず、挿入ソートを確認しましょう
//比如有组数据:
int[] arr = {
8, 6, 2, 3, 1, 5, 7, 4};
テキストの要約:最初の要素が最小の数値であると想定します。次に、index = 1から逆方向にループし、次の数値を順番に取り、前の数値と比較して最小の数値を見つける必要があります。つまり、インデックス= 1の場合、arr [1]がarr [0]と比較されます。インデックス= 2の場合、arr [2]とarr [1]を比較して最小値を取得し、次にarr [0]と比較します。最後に、小さいものから大きいものへのソートを完了します。
したがって、コードは次のとおりです
//{8, 6, 2, 3, 1, 5, 7, 4}
public void inseartSort(int[] arr) {
//所以外层循环,我们跳过第一个元素 8,拿后面的数和前面的数比较
for (int i = 1; i < arr.length; i++) {
//1、这层的循环是拿后面的数和前面的【依次比较】得出最小数
//2、下面内层循环不知道怎么写,我们可以先来拆分下逻辑
// (1)先看外层循环,index = 1,我们要拿arr[1]与arr[0]比较,较小的数字排在前面
// (2)继续看外层循环,index = 2,我们首先要拿arr[2]和arr[1]作比较,得出最小数后,继续和arr[0]做比较。
// 相当于index--了。
// (3)综上所述:外层循环的起始点,就是内层循环的起始点,其次index--才能依次和前面的数比较,做好排序。
// 既然是index--,那么index要满足的条件是index > 0 。不然异常。所以代码如下
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
}
}
}
}
第二に、ヒルソート
挿入ソートアルゴリズムを理解している。非常に長いデータのセット。ローカルで順序付けられた数値が多いほど、挿入ソートが効率的になり、パフォーマンスが向上します。
Hillアルゴリズム:この挿入ソートの特性を使用することで改善されます。彼はここに増分ギャップの概念を持っています。当面、インクリメンタルシーケンスによってもたらされる時間の複雑さについては説明しません。
それでもデータのセットである場合:{8、6、2、3、1、5、7、4}。ここでの増分は、gap = arr.length / 2であると想定します。つまり、4は配列を論理的にいくつかの部分にグループ化し(増分は複数の部分と見なすこともできます)、論理グループを順番に挿入して並べ替えますが、配列は同じ配列です。ソート後にギャップ/ = 2を使用します。それは2です。論理的にグループ化し続け、ソートを挿入し続けます。このように、元の配列のほとんどのデータは順序付けられたデータです。最後に、ギャップ= 1、ほとんどのデータが順序付けられたデータである配列のソートを挿入します。その後、速度ははるかに速くなり、パフォーマンスは便利で非常に効率的です。
それは非常に一般的かもしれません、分析を見てください
2.1、gap = 4の場合
ギャップ= 4の場合
- arr [0]およびarr [4]セット
- arr [1]およびarr [5]セット
- arr [2]およびarr [6]セット
- arr [3]およびarr [7]セット
//数据就对应如下
8 6 2 3 1 5 7 4
| | | | | | | |
8--|--|--|--1 | | |
6--|--|-----5 | |
2--|--------7 |
3-----------4
これは論理的なグループです。
- 8と1がソートされた後:1 8;
- 5と6がソートされた後:5 6;
- 2と7がソートされた後:2 7;
- 3と4がソートされた後:3 4。
8 6 2 3 1 5 7 4
| | | | | | | |
1--|--|--|--8 | | |
5--|--|-----6 | |
2--|--------7 |
3-----------4
垂直に見ると、ソート結果は次のとおりです。1 5 2 3 8 6 7 4
2.2、ギャップ= 2の場合
ギャップが2の場合、グループごとに2で区切られます。もちろん、2つのグループに分けられます。
1 5 2 3 8 6 7 4
| | | | | | | |
1--|--2--|--8--|--7 |
| | | |
| | | |
5-----3-----6-----4
gap = 2の場合のグループ化は
- 1 2 8 7;ソート後、1 2 7 8
- 5 3 6 4;ソート後、3 4 5 6
それで
1 5 2 3 8 6 7 4
| | | | | | | |
1--|--2--|--7--|--8 |
| | | |
| | | |
3-----4-----5-----6
垂直に見ると、ソート結果は次のとおりです。1 3 2 4 7 5 8 6
最後に、gap = 1の場合、通常の挿入ソートです。一部の人々は、あなたがそれを段階的に行う場合、最後のデータのセットはほとんどの数のために適切ではないと言うかもしれません。説明のため、比較的小さいデータサイズ= 8を選択しました。size> = 100000の場合、それは非常に明白です。
3、ヒルソートのJava式
上記の説明を通じて、私たちは知っています。実際、ヒルソートには増分という追加の概念がありますが、これはほとんど変更されていません
まず第一に、増分ギャップの変化を知っています
//不难理解,gap最终变化是4,2,1
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
}
次に、gap = 1を指定すると、通常の挿入ソートのコードが直接移動されます。
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
}
}
}
}
//上面式子看不大出来,我们把它变一下如下
//看看哪里时候把gap加上
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j >= 1; j-=1) {
//主要是修改了j>0 改成了 j>=1。 j-- 改成了 j-=1
if (arr[j] < arr[j - 1]) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
}
}
}
}
//改完之后,我们把gap=1的情况改成gap。也就是把1改成gap变化如下
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {
for (int j = i; j >= gap; j -= gap) {
if (arr[j] < arr[j - gap]) {
int temp = arr[j - gap];
arr[j - gap] = arr[j];
arr[j] = temp;
}
}
}
}
さて、これでヒルソーティングは終了です。次に、それを印刷して初期ロジックを確認します。