热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP排序算法之希尔排序

在插入排序中,如果数组元素的排列情况比较乐观,那么插入的次数就比较少,那么效率就很高了,可是很多时候,数据就是那么的不敬人意,比如如下的一个待\
希尔排序之交换排序

● 问题引入:

在插入排序中,如果数组元素的排列情况比较乐观,那么插入的次数就比较少,那么效率就很高了,可是很多时候,数据就是那么的不敬人意,比如如下的一个待 \

排序的数组:[2,3,4,5,6,7,1],这个数组,如果使用插入排序,那么就会发生如下的样子:

1. 第一轮:[2,3,4,5,6,7,7]

2. 第二轮:[2,3,4,5,6,6,7]

3. 第三轮:[2,3,4,5,5,6,7]

4. 第四轮:[2,3,4,4,5,6,7]

5. 第五轮:[2,3,3,4,5,6,7]

6. 第六轮:[2,2,3,4,5,6,7]

7. 第七轮:[1,2,3,4,5,6,7]

这样的就是最不乐观的情况,很浪费时间,所以,后来就有大神研究了一下,优化优化,就发明了希尔排序。

希尔排序 (Shell's Sort) 是插入排序的一种又称 “缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。

希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,

整个文件恰被分成一组,算法便终止

数组实例说明:

1. 比如有一个待排序的数组 [9,6,1,3,0,5.7,2,8,4]

2. 上面的数组一共有 10 个元素,它把数组第一次分为 10/2 = 5 组,然后两两比较,大小位置交换:如下:

 $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. 第二轮又开始比较,第二轮是在之前第一轮的基础上,再次分为 5/2 = 2 组,然后两两交换位置,大小指互换:如下:

 $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 组。也就是最后,每两个都要比较,然后再次互换位置

 $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]

完整代码如下:

 &#39;必须传入数组比较排序&#39;];
 }
 $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 [&#39;message&#39; => &#39;必须传入数组比较排序&#39;];
     }
 $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社区 其它相关文章!


推荐阅读
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文描述了作者第一次参加比赛的经历和感受。作者是小学六年级时参加比赛的唯一选手,感到有些紧张。在比赛期间,作者与学长学姐一起用餐,在比赛题目中遇到了一些困难,但最终成功解决。作者还尝试了一款游戏,在回程的路上感到晕车。最终,作者以110分的成绩取得了省一会的资格,并坚定了继续学习的决心。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 关羽败走麦城时路过马超封地 马超为何没有出手救人
    对当年关羽败走麦城,恰好路过马超的封地,为啥马超不救他?很感兴趣的小伙伴们,趣历史小编带来详细的文章供大家参考。说到英雄好汉,便要提到一本名著了,没错,那就是《三国演义》。书中虽 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 橱窗设计的表现手法及其应用
    本文介绍了橱窗设计的表现手法,包括直接展示、寓意与联想、夸张与幽默等。通过对商品的折、拉、叠、挂、堆等陈列技巧,橱窗设计能够充分展现商品的形态、质地、色彩、样式等特性。同时,寓意与联想可以通过象形形式或抽象几何道具来唤起消费者的联想与共鸣,创造出强烈的时代气息和视觉空间。合理的夸张和贴切的幽默能够明显夸大商品的美的因素,给人以新颖奇特的心理感受,引起人们的笑声和思考。通过这些表现手法,橱窗设计能够有效地传达商品的个性内涵,吸引消费者的注意力。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • faceu激萌变老特效的使用方法详解
    本文介绍了faceu激萌变老特效的使用方法,包括打开faceu激萌app、点击贴纸、选择热门贴纸中的变老特效,然后对准人脸进行拍摄,即可给照片添加变老特效。操作简单,适合新用户使用。 ... [详细]
author-avatar
重庆车管所
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有