實際上在,作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,對於排序是有影響的。結果就會影響展現效果。
*/