ヒルソート交換ソート
● 問題の導入:
挿入ソートでは、配列要素の配置が比較的楽観的である場合、この場合、挿入の数は比較的少なくなり、効率は非常に高くなりますが、多くの場合、ソートされる次の配列のように、データが非常に失礼になります: [2,3,4, 5,6,7] ,1]、挿入ソートが使用されている場合、この配列は次のようになります:
1. 最初のラウンド: [2,3,4,5,6,7, 7]
2. 第 2 ラウンド:[2,3,4,5,6,6,7]
3. 第 3 ラウンド:[2,3,4,5, 5,6,7]
4. 第 4 ラウンド:[2,3,4,4,5,6,7]
5. 第 5 ラウンド:[2,3, 3,4,5,6,7] ]
6. 第 6 ラウンド:[2,2,3,4,5,6,7]
7. 第 7 ラウンド:[ 1,2,3,4,5 ,6,7]
これは最も楽観的ではない状況であり、時間の無駄です。したがって、何人かの専門家が後にこれを研究し、最適化し、希望を生み出しました。
ヒル ソート (シェルズ ソート) は、挿入ソートの一種で、「ディミニッシング インクリメント ソート」 (ディミニシング インクリメント ソート) とも呼ばれ、直接挿入ソート アルゴリズムをより効率的に改良したバージョンです。
ヒルソートは、不安定なソートアルゴリズムです。この方法は、1959 年に D.L.Shell が提案したことにちなんで名付けられました。
ヒルソートとは、添字の特定の増分でレコードをグループ化し、直接挿入ソートアルゴリズムを使用して各グループをソートすることです。増分が徐々に減少するにつれて、各グループにはより多くのキーワードが含まれます。 1 に減らされると、
ファイル全体が 1 つのグループに分割され、アルゴリズムが終了します
#●配列例の説明:
1。たとえば, ソート対象の配列 [9,6,1,3,0,5.7,2,8,4]
2 があります。上記の配列には合計 10 個の要素があります。配列を次のように分割します。初回は 10 /2 = 5 グループ、次にそれらをペアで比較し、次のようにサイズと位置を交換します:<?php $arr = [9,6,1,3,0, 5,7,2,8,4]; $arr[0] > $arr[5] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置'; $arr[1] > $arr[6] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置'; $arr[2] > $arr[7] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置'; $arr[3] > $arr[8] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置'; $arr[4] > $arr[9] ? '交换位置,小数交换在前,大数交换在后' : '不交换位置'; for ($i = 5; $i < 10; $i++) { for ($j = $i - 5; $j >= 0; $j-=5) { if ($data[$j] > $data[$j+5]) { $temp = $data[$j]; $data[$j] = $data[$j+5]; $data[$j+5] = $temp; } } }最初のラウンドで得られた最終結果は次のとおりです: [5,6,1 ,3,0,9,7,2, 8,4]3. 比較の第 2 ラウンドが再び始まります。第 2 ラウンドは前の第 1 ラウンドに基づいており、5/2 = 2 に分割されます。次に、位置がペアで交換され、親指と小指が次のように交換されます:
<?php $arr = [5,6,1,3,0,9,7,2,8,4]; $arr[0] > $arr[2];//1,5 [1,6,5,3,0,9,7,2,8,4] $arr[2] > $arr[4];//0,5 [1,6,0,3,5,9,7,2,8,4] $arr[4] > $arr[6];//5,7 [1,6,0,3,5,9,7,2,8,4] $arr[6] > $arr[8];//7,8 [1,6,0,3,5,9,7,2,8,4] $arr[1] > $arr[3];//3,6 [1,3,0,6,5,9,7,2,8,4] $arr[3] > $arr[5];//6,9 [1,3,0,6,5,9,7,2,8,4] $arr[5] > $arr[7];//2,9 [1,3,0,6,5,2,7,9,8,4] $arr[7] > $arr[9];//4,9 [1,3,0,6,5,2,7,4,8,9] ... for ($i = 2; $i < 10; $i++) { for ($j = $i - 2; $j >= 0; $j-=2) { if ($data[$j] > $data[$j+2]) { $temp = $data[$j]; $data[$j] = $data[$j+2]; $data[$j+2] = $temp; } } }最終結果は次のようになります: [0,2,1,3,6,4,7, 6,8,9]4. 最後に再度グループ化します。比較します: 2/2 = 1 グループ。つまり、最終的に、それぞれ 2 つが比較され、位置が再び交換されます
<?php $arr = [0,2,1,3,5,4,7,6,8,9]; $arr[0] > $arr[1];//[1,3,0,6,5,2,7,4,8,9] $arr[1] > $arr[2];//[1,0,3,6,5,2,7,4,8,9] $arr[2] > $arr[3];//[1,0,3,6,5,2,7,4,8,9] $arr[3] > $arr[4];//[1,0,3,5,6,2,7,4,8,9] $arr[4] > $arr[5];//[1,0,3,5,2,6,7,4,8,9] $arr[5] > $arr[6];//[1,0,3,5,2,6,7,4,8,9] $arr[6] > $arr[7];//[1,0,3,5,2,6,4,7,8,9] $arr[7] > $arr[8];//[1,0,3,5,2,6,4,7,8,9] $arr[8] > $arr[9];//[1,0,3,5,2,6,4,7,8,9] ... for ($i = 1; $i < 10; $i++) { for ($j = $i - 1; $j >= 0; $j-=1) { if ($data[$j] > $data[$j+1]) { $temp = $data[$j]; $data[$j] = $data[$j+1]; $data[$j+1] = $temp; } } }最終的に、結果が得られます: [0,1,2,3,4,5,6,7, 8,9]●
完全なコードは次のとおりです:
<?php class ShellSort { /*** Notes: 希尔排序之交换法排序 * User: LiYi\ * Date: 2019/11/12 0012\ * Time: 14:30\ * @param array $data\ * @return array\ */\ public static function shellSortArray(array $data):array { if (!is_array($data)) { return ['message' => '必须传入数组比较排序']; } $count = count($data);//得到数组的个数 //如果数组的个数小于等于1就直接返回 if ($count <= 1) {return $data;} //$gap 是每次减半的分组,直到只可以分为一组结束,在php里面需要注意,两个整数相除,除不尽的情况下,得到的是一个浮点数,不是一个向下 //取整的的整数,所以在最后判断gap 退出循环的时候,需要判断它 >= 1 for ($gap = $count / 2; $gap >= 1; $gap /= 2) { for ($i = $gap; $i < $count; $i++) { for ($j = $i - $gap; $j >= 0; $j-=$gap) { if ($data[$j] > $data[$j+$gap]) { //这个地方是比较第一个数和它的步长做比较,交换也是一样 $temp = $data[$j]; $data[$j] = $data[$j+$gap]; $data[$j+$gap] = $temp; } } } } return $data; } public static function validate(array $data) { if (!is_array($data)) { return ['message' => '必须传入数组比较排序']; } $count = count($data);//得到数组的个数 //如果数组的个数小于等于1就直接返回 if ($count <= 1){ return $data; } return [$data, $count]; } /**\ * Notes: 希尔排序之移位法排序 * User: LiYi * Date: 2019/11/12 0012 * Time: 14:29 * @param array $data * @return array*/ public static function ShellSortMoveArray(array $data) { $count = count($data);//得到数组总数 for ($gap = $count / 2; $gap > 0; $gap /= 2) { //缩小增量,每次减半 $gap = floor($gap); for ($i = $gap; $i < $count; $i++) { // $insertIndex = $i;//待插入元素的下表 $insertValue = $data[$insertIndex];//待插入元素的值 echo "insertIndex=$insertIndex" . PHP_EOL; echo "insertValue=$insertValue" . PHP_EOL; if ($data[$insertIndex] < $data[$insertIndex - $gap]) { //判断待插入元素和它步长的元素比较,待插入元素小就进入循环 //判断是否越界了,第一个元素的下标是要大于等于0的,否则退出循环 //判断后面的元素比前面的元素小,进入循环,否则退出循环 while ($insertIndex - $gap >= 0 && $insertValue < $data[$insertIndex - $gap]) { //把步长前面的大的值向后移动 $data[$insertIndex] = $data[$insertIndex - $gap]; $insertIndex -= $gap;//每循环一次就把带插入的坐标减去补偿\ } //把带插的小值插入到前面 $data[$insertIndex] = $insertValue; } } } return $data; } public static function testShellOne(array $data) { $temp = 0; $count = count($data); for ($i = 5; $i < $count; $i++) { for ($j = $i - 5; $j >= 0; $j-=5) { if ($data[$j] > $data[$j+5]) { $temp = $data[$j]; $data[$j] = $data[$j+5]; $data[$j+5] = $temp; } } } for ($i = 2; $i < $count; $i++) { for ($j = $i - 2; $j >= 0; $j-=2) { if ($data[$j] > $data[$j+2]) { $temp = $data[$j]; $data[$j] = $data[$j+2]; $data[$j+2] = $temp; } } } for ($i = 1; $i < 10; $i++) { for ($j = $i - 1; $j >= 0; $j-=1) { if ($data[$j] > $data[$j+1]) { $temp = $data[$j]; $data[$j] = $data[$j+1]; $data[$j+1] = $temp; } } } var_dump($data); } } var_dump(ShellSort::shellSortMoveArray([0 => 9, 1 => 6, 2 => 1, 3 => 3, 4 => 0, 5 => 5, 6 => 7, 7 => 2, 8 => 8, 9 => 4])); // $gap = 10 / 2 = 5 // $insertIndex = $i = $gap = 5 // $insertValue = $data[$insertIndex] = $data[5] = 5; // $data[$insertIndex] < $data[$insertIndex - $gap] == $data[5] < $data[5-5] = $data[0] ==> 5 < 9 // while(5 - 5 >= 0 && 5 < 9) { // $data[5] = $data[5-5] = $data[0] = 9 // $insertIndex -= 5 = 0; //} // $data[$insertIndex] = $data[0] = $insertValue = 5 // $i++ = 6; // $insertIndex = $i = 6 // $insertValue = $data[$insertIndex] = $data[6] = 7; // $data[$insertIndex] < $data[$insertIndex - $gap] == $data[6] < $data[6-5] = $data[1] ==> 7 < 6 // $i++ = 7; // $insertIndex = $i = 7 // $insertValue = $data[$insertIndex] = $data[7] = 2; // $data[$insertIndex] < $data[$insertIndex - $gap] == $data[7] < $data[7-5] = $data[2] ==> 2 < 1 // $i++ = 8; // $insertIndex = $i = 8 // $insertValue = $data[$insertIndex] = $data[8] = 8; // $data[$insertIndex] < $data[$insertIndex - $gap] == $data[8] < $data[8-5] = $data[3] ==> 8 < 3 // $i++ = 9; // $insertIndex = $i = 9 // $insertValue = $data[$insertIndex] = $data[9] = 4; // $data[$insertIndex] < $data[$insertIndex - $gap] == $data[9] < $data[9-5] = $data[4] ==> 4 < 0
以上がPHP ソート アルゴリズム ヒル ソートの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。