php项目开发中用到的快速排序算法分析


Posted in PHP onJune 25, 2016

本文实例讲述了php项目开发中用到的快速排序算法。分享给大家供大家参考,具体如下:

实际上在,做web开发,比较少遇到使用一些算法之类的,毕竟不是做搜索引擎,也不是写底层(比如写个类似于mysql这样的数据库,里面需要自己实现排序算法),另外,每种语言,比如java,php都或多或少已经封装好排序函数给程序员使用。比如有个共识,大家做web开发的基本都明白,业务逻辑多比较简单,不是很复杂的业务逻辑。我们作为web开发的程序员,基本是是web架构,对数据库增删查改数据,然后把数据展示在页面中,大多就是涉及性能优化,缓存等等。

学学一些常见的算法,对于实现特殊的应用还是有帮助的。比如有些时候我们依赖于数据库中order by来实现排序了,所以非常习惯直接接下交给数据库实现排序了。

接下来,我就遇到需要自己实现排序了。

​因为我们在实际开发中,遇到一个问题,完全需要我自己实现排序。需求如下:

在商品表里面,有一个字段是goods_price(商品价格),现在要开发一个促销价功能。促销价有个时间范围设置。在前台页面中,展示商品的时候。如果当前时间符合促销时间。就要按照促销价格执行。于是促销价就单独增加了一个字段来保存,叫做promote_price,促销时间配置信息比如什么时间,每天几点到几点之类的时间设置信息暂时不管,存储在其他字段中的,展示的时候,要用当前时间跟配置的时间进行比较。

单条商品展示的时候,就直接判断是否在促销时间内即可了。没遇到排序的问题。

而是在做商品列表页面的时候,一个这样的小细节就让我发现需求:用户可以选择商品价格按照"从高到低"也可以选择"从低到高"排序。

如果是单纯排序,以往是直接交给数据库去排序,一般我们习惯了sql中使用"order by goods_price DESC"之类的语句就能实现按照价格降序还是升序进行。

现在,不能简单就按照goods_price(商品价格)排序就ok。比如当前时间有的商品是符合促销时间的,那么促销价也是要作为排序的。

简单的 order by goods_price DESC,promote_price DESC 这种做法的话完全是不对路现在的需求。

所以呢,需要先对交给数据库的order by goods_price DESC 排序一次,列出数据。

然后遍历,看哪些商品数据是符合促销价格的。然后自己编写代码实现排序。

我初期想法是:拿到当前页的数据,里面判断每行是否符合促销价时间点

foreach(经过数据库按照价格字段排序的结果)
{
if ($v['promote_price'] > 0 && $promote_class->promtoe_validate($food_info)) {
      $v['is_promote'] = true;
      $v['price']= $v['promote_price'];
      //将原价改为促销价显示
    }
}

对上面的列表,因为上面的列表经过mysql排序一次后,还经过了促销价。所以还需要再次编写一个排序算法排序一次。这样就可以把促销价低的放到前面去了

其实,mysql数据库就是用c语言编写的。我理解数据库order by,它的排序也就是用c语言实现对数组的排序(关系表里面返回的的行列表就是一个二维数组)

只是,平时我们排序是交给数据库去实现了。很少自己编写,所以因为接触不多,就以为这些算法自己用不上,现在仍然需要用php语言对数据去实现排序。

数据库中的 order by a DESC,b ASC  的实现原理猜测?

第一种理解:先按照a字段进行排序。然后又对数据按照b字段进行排序。
第二种理解:先按照a字段进行排序 ,如果遇到两个值相同的,无法确定谁在前在后时,则使用b asc来确定两个数据的先后顺序。

我是第一种理解,后来纠正,第二种理解才是对符合对的,因为这才比较符合设计的考虑点:

为什么要设计可以多个字段进行排序?难道是为了相互覆盖掉吗?比如先按照a字段排序了。某两项数据本来是一个在前一个在后,如果又按照b asc进行排序,那么可能原来这两项数据的顺序就可能错位,就是可能导致后面的排序规则应用后的结果覆盖前面的。

假设数据库排序是这样子设计的话就没实际意义了。之所以设计多个字段进行排序。就是为了解决,遇到两行中a字段的值都2,2的时候,怎么确定先后?这个时候就调用后面的排序规则对这两项数据排序。所以order by 后面的字段先后顺序不同造成的效果是不同的。

现实生活例子:假设要排名100个学生的英语成绩,假设排序的时候,遇到三个学生都是88分。谁排名在前呢?这个时候可以附加一种新的排序方式,对这三个学生看他们的品行分排序。这样子就好确定了。

网上的快速排序法,实现都是针对一维数组来实现的。现在我要模拟数据库中的行,也就是二维数组作为参数,并且可以指定任意字段作为排序方式。

比如从数据库中查询出一个数据列表,原封不动的对这个列表可以指定某个字段进行排序(数据库就是实现这个需求吧。当然他们要先进得些。人家牛逼些 呵呵。

具体,看下面:

/*
 * 排序:此函数是一个通用函数,只要是二维数组的排序都可以调用。初衷是解决价格快速排序(涉及到促销价,无法使用order by解决)
 * +--------------------------------------------------------------------------
 * @param $arr 要排序的数组,二维数组。对应就是数据库中的多行数据 array(
 * 0=>array("字段1"=>'','字段2'=>''...)
 * 1=>array("字段1"=>'','字段2'=>''...)
 * 2=>array("字段1"=>'','字段2'=>''...)
 * )
 * +--------------------------------------------------------------------------
 * @param $key_field 按照哪个字段进行排序,不要传入一个并不存在的字段。会打乱原来的顺序
 * +--------------------------------------------------------------------------
 * @param $sort_type = asc or desc 排序方式。从小大到大,还是从大到小
 */
function quickSort($arr, $key_field, $sort_type = "asc") {
  if (count($arr) > 1) {
    //使用哪个字段排序,先得到该字段所有数据,目的是转换成一维数组进行排序
    $key_value_arr = array();
    $return_arr = array();
    //先判断排序的字段是否存在
    foreach ($arr as $k => $v) {
      $key_value_arr[$k] = $v[$key_field]; //得到这个字段的值
    }
    //php内置函数实现了按降序还是升序排,但是只支持一维数组
    if ($sort_type == 'desc') {
      arsort($key_value_arr);
    } else {
      asort($key_value_arr);
    }
    reset($key_value_arr);
    foreach ($key_value_arr as $k => $v) {
      $return_arr[$k] = $arr[$k]; //得到行
    }
    return $return_arr;
  } else {
    return $arr;
  }
}

总结一下我对快速排序法的理解

假设有100个元素,对此进行排序。那么需要遍历多少次呢?仍然需要遍历至少100次。因为确实都免不了,逐个去扫描每个元素,丢到左边,还是右边。当第一次分割之后。还要继续对分割后两边的进行重复这一步骤。
当元素数量小的时候,是体会不到区别的。如果数量很大,达到上万个元素。需要进行排序,则需要涉及到算法了
比如比较高矮,现实中情况,我们人可以用眼睛来看,哪个更小,然后认为的排序出来。但是计算机则不同。我们必须编写程序来告诉它要什么样的方法实现。

快速排序体现的思想是:分治法。分割成小块,逐个解决。

大体的思路描述:

1、从一堆数据里面找到一个基准的数据。按照这个数据标准分割开来。现实例子,一堆人100个人,比较高矮。现在我找出一个高度的人,我按照这个人的身高,分成a,b两组。比他矮的都站到a组,比他高的都站到b(跟他一样高的随便放哪一边都可以),这样子可将100个人分割成两组人。
结果是,a组里面的所有人身高都要<=b组里面的人。
2、对a组里面的人重复第一步。对b组里面的人也重复第一步。
3、直到最后只剩下一个(因为已经没法在继续切割了),才分组。

我学到一个思想:先切成大块,然后对每个大块单独处理。最后把各个块的处理结果都合并起来。

function quickSort($arr) {
 if(count($arr) > 1) {
  $k=$arr[0];
  $x=array();
  $y=array();
  $_size=count($arr);  
  for($i=1;$i<$_size;$i++) {
   if($arr[$i] <=$k) {
    $x[] =$arr[$i];//小的放这边
   }else{
    $y[] =$arr[$i];//大的放这边。这样子是从小到大排序,如果想从大到小返回,那么调换位置与$x[] =$arr[$i];的位置即可
   }
  }
   //得到分割看来左右两边的数据
  $x= quickSort($x);//左边的数据,对这些数据再次使用分割法排序,返回的结果就是排序后的数据
  $y= quickSort($y);//右边的数据
  returnarray_merge($x,array($k),$y);
 }else{
  return$arr;
 }
}

不正确之处,欢迎指正!

代码备份:

<?php
//大体思路:由于是二维数组。所以先得到指定key的所有值。也就是转换为一维数组了。
/*
不过这个一维数组的key要使用二维数组的key。这样子一维数组排序后,方便对应到二维数组中去。就是靠这个key。
一维数组如下:
array('1'=>'a','4'=>''b','3'=>'c','5'=>'d');
1,2,4这些key值,到时候就是对应到里面去的证据
思考,如果还要加一个条件呢比如像sql那样子的:order by a,b,c
当a字段的值都相等的情况下,就启用b字段进行排序。如果还是相等,则启用c字段进行排序。
*/
/*
$keys = array();
$keys['gg'] = '8.9';
$keys[1] = '8.8';
$keys[5] = '7.5';
asort($keys);//排序有个特点,原来的key值不会改变的。只是把位置换一下。我之前以为是调换了key值。这样子,0,1,2,3,4
reset($keys);
var_dump($keys);
*/
/*
 * +-------------------------------------------------------
 * 快速排序
 * @author wangtao 2015.6.10
 * +-------------------------------------------------------
 * @param $arr 要排序的数组,二维数组。对应就是数据库中的多行数据
 array(
 * 0=>array("字段1"=>'','字段2'=>''...)
 * 1=>array("字段1"=>'','字段2'=>''...)
 * 2=>array("字段1"=>'','字段2'=>''...)
 * )
 * @param $key_field 按照哪个字段进行排序
 * @param $sort_type = asc or desc 排序方式。从小大到大,还是从大到小
 * +-------------------------------------------------------
 * return 按照指定排序后的一个新数组。原来的key仍然会保留
 * 如:1=>array("字段1"=>'','字段2'=>''...),2=>array("字段1"=>'','字段2'=>''...) 
 * 按照"字段2"排序后,key为2元素可能在前面前面了,但是key值不会被修改,会原样保留
 * +-------------------------------------------------------
 */
function quick_sort($arr, $key_field, $sort_type = "asc") {
  if (count($arr) > 1) {
    //使用哪个字段排序,先得到该字段所有数据,目的是转换成一维数组进行排序
    $key_value_arr = array();
    $return_arr = array();
    //先判断排序的字段是否存在,如果字段根本不存在,避免打乱原来数组的顺序
    foreach ($arr as $k => $v) {
      @ $key_value_arr[$k] = $v[$key_field]; //得到这个字段的值
    }
    //php内置函数实现了按降序还是升序排,但是只支持一维数组
    if ($sort_type == 'desc') {
      arsort($key_value_arr);
    } else {
      asort($key_value_arr);
    }
    reset($key_value_arr);
    foreach ($key_value_arr as $k => $v) {
      $return_arr[$k] = $arr[$k]; //得到行
    }
    //var_dump($return_arr);
    return $return_arr;
  } else {
    return $arr;
  }
}
$array = array(
array('name'=>'手机','brand'=>'诺基亚','price'=>1050),
array('name'=>'笔记本电脑','brand'=>'lenovo','price'=>4300),
array('name'=>'剃须刀','brand'=>'飞利浦','price'=>3100),
array('name'=>'跑步机','brand'=>'三和松石','price'=>4900),
array('name'=>'手表','brand'=>'卡西欧','price'=>960),
array('name'=>'液晶电视','brand'=>'索尼','price'=>6299),
array('name'=>'激光打印机','brand'=>'惠普','price'=>1200),
array('name'=>'手机','brand'=>'诺基亚','price'=>1050),
);
var_dump(quickSort($array,'m'));
//看对一个数组里面元素值都为空的怎么排序
$row = array(
0=>null,
1=>null,
2=>null,
3=>null,
);
asort($row);
var_dump($row);//如果为空。则根据key值倒过来?
/*返回的是array
 3 => null
 2 => null
 1 => null
 0 => null
现在终于明白了,数据库字段中是否保持null,对于排序是有影响的。结果就会影响展示效果。
*/

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php&amp;java(二)
Oct 09 PHP
PHP4在Windows2000下的安装
Oct 09 PHP
hadoop中一些常用的命令介绍
Jun 19 PHP
跟我学Laravel之配置Laravel
Oct 15 PHP
实现PHP+Mysql无限分类的方法汇总
Mar 02 PHP
php导出中文内容excel文件类实例
Jul 06 PHP
PHP如何通过传引用的思想实现无限分类(代码简单)
Oct 13 PHP
PHP统计当前在线用户数实例讲解
Oct 21 PHP
PHP生成和获取XML格式数据的方法
Mar 04 PHP
浅谈PHP中其他类型转化为Bool类型
Mar 28 PHP
PHP抽象类与接口的区别详解
Mar 21 PHP
修改Laravel自带的认证系统的User类的命名空间的步骤
Oct 15 PHP
php函数传值的引用传递注意事项分析
Jun 25 #PHP
php好代码风格的阶段性总结
Jun 25 #PHP
php编译安装php-amq扩展简明教程
Jun 25 #PHP
将PHP的session数据存储到数据库中的代码实例
Jun 24 #PHP
php自动载入类用法实例分析
Jun 24 #PHP
php模拟post上传图片实现代码
Jun 24 #PHP
一个简单安全的PHP验证码类 附调用方法
Jun 24 #PHP
You might like
PHP与MySQL开发中页面乱码的产生与解决
2008/03/27 PHP
Php output buffering缓存及程序缓存深入解析
2013/07/15 PHP
PHP5.3连接Oracle客户端及PDO_OCI模块的安装方法
2016/05/13 PHP
AJAX跨域请求json数据的实现方法
2013/11/11 Javascript
js动态修改整个页面样式达到换肤效果
2014/05/23 Javascript
js中string转int把String类型转化成int类型
2014/08/13 Javascript
jQuery插件实现大图全屏图片相册
2015/03/14 Javascript
JavaScript高级程序设计(第三版)学习笔记6、7章
2016/03/11 Javascript
全面了解JS中的匿名函数
2016/06/29 Javascript
AngularJS ng-change 指令的详解及简单实例
2016/07/30 Javascript
jQuery遍历节点树方法分析
2016/09/08 Javascript
javascript实现消灭星星小游戏简单版
2016/11/15 Javascript
详解Angularjs在控制器(controller.js)中使用过滤器($filter)格式化日期/时间实例
2017/02/17 Javascript
解决Node.js使用MySQL出现connect ECONNREFUSED 127.0.0.1:3306的问题
2017/03/09 Javascript
JS实现的添加弹出层并完成锁屏操作示例
2017/04/07 Javascript
js断点调试经验分享
2017/12/08 Javascript
Vue项目中如何引入icon图标
2018/03/28 Javascript
[00:58]他们到底在电话里听到了什么?
2017/11/21 DOTA
Python类的基础入门知识
2008/11/24 Python
python使用cookielib库示例分享
2014/03/03 Python
Ubuntu 下 vim 搭建python 环境 配置
2017/06/12 Python
Python实现自动发送邮件功能
2021/03/02 Python
linecache模块加载和缓存文件内容详解
2018/01/11 Python
python 数据生成excel导出(xlwt,wlsxwrite)代码实例
2019/08/23 Python
python同时遍历两个list用法说明
2020/05/02 Python
python3+opencv 使用灰度直方图来判断图片的亮暗操作
2020/06/02 Python
PyCharm2019.3永久激活破解详细图文教程,亲测可用(不定期更新)
2020/10/29 Python
Python大批量搜索引擎图像爬虫工具详解
2020/11/16 Python
工程部经理岗位职责
2013/12/08 职场文书
高三家长寄语
2014/04/03 职场文书
2014年巴西世界杯口号
2014/06/05 职场文书
公司领导班子对照材料
2014/08/18 职场文书
2014年师德师风工作总结
2014/11/25 职场文书
2014年信息技术工作总结
2014/12/16 职场文书
pytorch 带batch的tensor类型图像显示操作
2021/05/20 Python
如何用PHP实现多线程编程
2021/05/26 PHP