开发中用到的一个快速排序法

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

 

学学一些常见的算法,对于实现特殊的应用仍是有帮助的。好比有些时候咱们依赖于数据库中order by来实现排序了,因此很是习惯直接接下交给数据库实现排序了。java

接下来,我就遇到须要本身实现排序了。mysql

 

由于咱们在实际开发中,遇到一个问题,彻底须要我本身实现排序。需求以下:程序员

 

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

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

 

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

若是是单纯排序,以往是直接交给数据库去排序,通常咱们习惯了sql中使用"order by goods_price DESC"之类的语句就能实现按照价格降序仍是升序进行。算法

 

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

 

简单的 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次。由于确实都免不了,逐个去扫描每一个元素,丢到左边,仍是右边。当第一次分割以后。还要继续对分割后两边的进行重复这一步骤。

 

当元素数量小的时候,是体会不到区别的。若是数量很大,达到上万个元素。须要进行排序,则须要涉及到算法了

 

好比比较高矮,现实中状况,咱们人能够用眼睛来看,哪一个更小,而后认为的排序出来。可是计算机则不一样。咱们必须编写程序来告诉它要什么样的方法实现。

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

 

大致的思路描述:

一、从一堆数据里面找到一个基准的数据。按照这个数据标准分割开来。现实例子,一堆人100我的,比较高矮。如今我找出一个高度的人,我按照这我的的身高,分红a,b两组。比他矮的都站到a组,比他高的都站到b(跟他同样高的随便放哪一边均可以),这样子可将100我的分割成两组人。

 

结果是,a组里面的全部人身高都要<=b组里面的人。

 

二、对a组里面的人重复第一步。对b组里面的人也重复第一步。

 

三、直到最后只剩下一个(由于已经无法在继续切割了),才分组。

 

 

 

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

 

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 );//右边的数据
     return array_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,对于排序是有影响的。结果就会影响展现效果。
*/

复制代码

相关文章
相关标签/搜索