可以使用自定義函數(shù)排序uasort(),搭配匿名函數(shù)挺方便的
我們提供的服務(wù)有:網(wǎng)站制作、成都網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、惠濟(jì)ssl等。為成百上千企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的惠濟(jì)網(wǎng)站制作公司
$array = array('a' = 4, 'b' = 8, 'c' = -1, 'd' = -9, 'e' = 2, 'f' = 5, 'g' = 3, 'h' = -4);
uasort($array,function($a,$b){
if ($a == $b) {
return 0;
}
return ($a $b) ? -1 : 1;
});
print_r($array);
如果你已經(jīng)使用了一段時間PHP的話,那么,你應(yīng)該已經(jīng)對它的數(shù)組比較熟悉了——這種數(shù)據(jù)結(jié)構(gòu)允許你在單個變量中存儲多個值,并且可以把它們作為一個集合進(jìn)行操作。
經(jīng)常,開發(fā)人員發(fā)現(xiàn)在PHP中使用這種數(shù)據(jù)結(jié)構(gòu)對值或者數(shù)組元素進(jìn)行排序非常有用。PHP提供了一些適合多種數(shù)組的排序函數(shù),這些函數(shù)允許你在數(shù)組內(nèi)部對元素進(jìn)行排列,也允許用很多不同的方法對它們進(jìn)行重新排序。在這篇文章中我們將討論該排序中最重要的幾個函數(shù)。
簡單排序
首先,讓我們來看看最簡單的情況:將一個數(shù)組元素從低到高進(jìn)行簡單排序,這個函數(shù)既可以按數(shù)字大小排列也可以按字母順序排列。PHP的sort()函數(shù)實現(xiàn)了這個功能,如Listing A所示:
Listing A
?php
? $data = array(5,8,1,7,2);
? sort($data);
? print_r($data);
? ?
輸出結(jié)果如下所示:
Array ([0] = 1
[1] = 2
[2] = 5
[3] = 7
[4] = 8
)
也能使用rsort()函數(shù)進(jìn)行排序,它的結(jié)果與前面所使用的sort()簡單排序結(jié)果相反。Rsort()函數(shù)對數(shù)組元素進(jìn)行從高到低的倒排,同樣可以按數(shù)字大小排列也可以按字母順序排列。Listing B給我們展示了它的一個例子:
Listing B
?php $data = array(5,8,1,7,2);rsort($data); print_r($data);
?
它的輸出結(jié)果如下:
Array ([0] = 8
[1] = 7
[2] = 5
[3] = 2
[4] = 1
)
根據(jù)關(guān)鍵字排序
當(dāng)我們使用數(shù)組的時候,經(jīng)常根據(jù)關(guān)鍵字對數(shù)組重新排序,從高到低。Ksort()函數(shù)就是根據(jù)關(guān)鍵字進(jìn)行排序的函數(shù),同時,它在排序的過程中會保持關(guān)鍵字的相關(guān)性。Listing C就是一個例子:
Listing C
?php $data = array("US" = "United States", "IN" = "India", "DE" = "Germany", "ES" = "Spain");ksort($data); print_r($data);
?
它的輸出結(jié)果如下:
Array ([DE] = Germany
[ES] = Spain
[IN] = India
[US] = United States
)
Krsort()函數(shù)是根據(jù)關(guān)鍵字對數(shù)組進(jìn)行倒排,Listing D就是這樣的例子:
Listing D
?php $data = array("US" = "United States", "IN" = "India", "DE" = "Germany", "ES" = "Spain");krsort($data); print_r($data);
?
它的輸出結(jié)果如下:
Array ([US] = United States
[IN] = India
[ES] = Spain
[DE] = Germany
)
根據(jù)值排序
如果你想使用值排序來取代關(guān)鍵字排序的話,PHP也能滿足你的要求。你只要使用asort()函數(shù)來代替先前提到的ksort()函數(shù)就可以了。如Listing E所示:
Listing E
?php $data = array("US" = "United States", "IN" = "India", "DE" = "Germany", "ES" = "Spain");asort($data); print_r($data);
?
下面就是它的輸出結(jié)果。請注意這個結(jié)果與上面使用ksort()函數(shù)所得到的結(jié)果的不同——在這兩種情況中,都是按字母順序進(jìn)行排序的,但是它們是根據(jù)數(shù)組的不同字段進(jìn)行排序的。
同時,請注意關(guān)鍵字-值之間的聯(lián)系會始終保持;它只是關(guān)鍵字-值對排序后的一種方式,排序并不會改變它們的對應(yīng)關(guān)系。
Array ([DE] = Germany
[IN] = India
[ES] = Spain
[US] = United States
)
現(xiàn)在,你肯定能猜到這種排序也可以進(jìn)行倒排,它使用arsort()函數(shù)完成這個功能。Listing F就是一個例子:
Listing F
?php $data = array("US" = "United States", "IN" = "India", "DE" = "Germany", "ES" = "Spain");arsort($data); print_r($data);
?
下面是它的輸出結(jié)果,根據(jù)值按字母表順序進(jìn)行倒排。將下面的結(jié)果與用krsort()函數(shù)進(jìn)行倒排后生成的結(jié)果進(jìn)行比較,就能很容易明白兩者的不同了。
Array ([US] = United States
[ES] = Spain
[IN] = India
[DE] = Germany
)
自然語言排序
PHP有一個非常獨特的排序方式,這種方式使用認(rèn)知而不是使用計算規(guī)則。這種特性稱為自然語言排序,當(dāng)創(chuàng)建模糊邏輯應(yīng)用軟件的時候這種排序方式非常有用。下面大家可以來看看它的一個簡單例子,如Listing G所示:
Listing G
?php $data = array("book-1", "book-10", "book-100", "book-5"); sort($data);print_r($data);
natsort($data); print_r($data);?
它的輸出結(jié)果如下:
Array ([0] = book-1
[1] = book-10
[2] = book-100
[3] = book-5
)
Array
(
[0] = book-1
[3] = book-5
[1] = book-10
[2] = book-100
)
它們的不同已經(jīng)很清楚了:第二個排序結(jié)果更直觀,更“人性化”,然而第一個則更符合算法規(guī)則,更具“計算機”特點。
自然語言能進(jìn)行倒排嗎?答案是肯定的!只要對natsort()的結(jié)果使用array_reverse()函數(shù)就可以了,Listing H就是一個簡單例子:
Listing H
?php $data = array("book-1", "book-10", "book-100", "book-5");natsort($data); print_r(array_reverse($data));
?
下面是它的輸出結(jié)果:
Array ([0] = book-100
[1] = book-10
[2] = book-5
[3] = book-1
)
根據(jù)用戶自定義的規(guī)則排序
PHP也能讓你定義自己的排序算法,你可以通過創(chuàng)建你自己的比較函數(shù),并把它傳遞給usort()函數(shù)。如果第一個參數(shù)比第二個參數(shù)“小”的話,比較函數(shù)必須返回一個比0小的數(shù),如果第一參數(shù)比第二個參數(shù)“大”的話,比較函數(shù)應(yīng)該返回一個比0大的數(shù)。
Listing I就是這樣的一個例子,在這個例子中根據(jù)它們的長度對數(shù)組元素進(jìn)行排序,最短的項放在最前面:
Listing I
?php $data = array("joe@host.com", "john.doe@gh.co.uk", "asmithsonian@us.info", "jay@zoo.tw");usort($data, 'sortByLen');
print_r($data); function sortByLen($a, $b) {
if (strlen($a) == strlen($b)) {
return 0;
} else {
return (strlen($a) strlen($b)) ? 1 : -1;
}
}
?
這樣,就創(chuàng)建了我們自己的比較函數(shù),這個函數(shù)使用strlen()函數(shù)比較每一個字符串的個數(shù),然后分別返回1,0或-1.這個返回值是決定元素排列的基礎(chǔ)。下面是它的輸出結(jié)果:
Array ([0] = jay@zoo.tw
[1] = joe@host.com
[2] = john.doe@gh.co.uk
[3] = asmithsonian@us.info
)
自然語言排序
PHP有一個非常獨特的排序方式,這種方式使用認(rèn)知而不是使用計算規(guī)則。這種特性稱為自然語言排序,當(dāng)創(chuàng)建模糊邏輯應(yīng)用軟件的時候這種排序方式非常有用。下面大家可以來看看它的一個簡單例子,如Listing G所示:
Listing G
?php $data = array("book-1", "book-10", "book-100", "book-5"); sort($data);print_r($data);
natsort($data); print_r($data);?
它的輸出結(jié)果如下:
Array ([0] = book-1
[1] = book-10
[2] = book-100
[3] = book-5
)
Array
(
[0] = book-1
[3] = book-5
[1] = book-10
[2] = book-100
)
它們的不同已經(jīng)很清楚了:第二個排序結(jié)果更直觀,更“人性化”,然而第一個則更符合算法規(guī)則,更具“計算機”特點。
自然語言能進(jìn)行倒排嗎?答案是肯定的!只要對natsort()的結(jié)果使用array_reverse()函數(shù)就可以了,Listing H就是一個簡單例子:
Listing H
?php $data = array("book-1", "book-10", "book-100", "book-5");natsort($data); print_r(array_reverse($data));
?
下面是它的輸出結(jié)果:
Array ([0] = book-100
[1] = book-10
[2] = book-5
[3] = book-1
)
根據(jù)用戶自定義的規(guī)則排序
PHP也能讓你定義自己的排序算法,你可以通過創(chuàng)建你自己的比較函數(shù),并把它傳遞給usort()函數(shù)。如果第一個參數(shù)比第二個參數(shù)“小”的話,比較函數(shù)必須返回一個比0小的數(shù),如果第一參數(shù)比第二個參數(shù)“大”的話,比較函數(shù)應(yīng)該返回一個比0大的數(shù)。
Listing I就是這樣的一個例子,在這個例子中根據(jù)它們的長度對數(shù)組元素進(jìn)行排序,最短的項放在最前面:
Listing I
?php $data = array("joe@host.com", "john.doe@gh.co.uk", "asmithsonian@us.info", "jay@zoo.tw");usort($data, 'sortByLen');
print_r($data); function sortByLen($a, $b) {
if (strlen($a) == strlen($b)) {
return 0;
} else {
return (strlen($a) strlen($b)) ? 1 : -1;
}
}
?
這樣,就創(chuàng)建了我們自己的比較函數(shù),這個函數(shù)使用strlen()函數(shù)比較每一個字符串的個數(shù),然后分別返回1,0或-1.這個返回值是決定元素排列的基礎(chǔ)。下面是它的輸出結(jié)果:
Array ([0] = jay@zoo.tw
[1] = joe@host.com
[2] = john.doe@gh.co.uk
[3] = asmithsonian@us.info
)
多維排序
最后,PHP也允許在多維數(shù)組上執(zhí)行一些比較復(fù)雜的排序——例如,首先對一個嵌套數(shù)組使用一個普通的關(guān)鍵字進(jìn)行排序,然后再根據(jù)另一個關(guān)鍵字進(jìn)行排序。這與使用SQL的ORDER BY語句對多個字段進(jìn)行排序非常相似。為了能更好的明白它是如何工作的,請仔細(xì)看Listing J所舉的例子:
Listing J
?php $data = array(array("id" = 1, "name" = "Boney M", "rating" = 3),
array("id" = 2, "name" = "Take That", "rating" = 1),
array("id" = 3, "name" = "The Killers", "rating" = 4),
array("id" = 4, "name" = "Lusain", "rating" = 3),
); foreach ($data as $key = $value) {
$name[$key] = $value['name'];
$rating[$key] = $value['rating'];
}
array_multisort($rating, $name, $data); print_r($data);?
這里,我們在$data數(shù)組中模擬了一個行和列數(shù)組。然后,我使用array_multisort()函數(shù)對數(shù)據(jù)集合進(jìn)行重排,首先是根據(jù)rating進(jìn)行排序,然后,如果rating相等的話,再根據(jù)name排序。它的輸出結(jié)果如下:
Array ([0] = Array
(
[id] = 2
[name] = Take That
[rating] = 1
) [1] = Array
(
[id] = 1
[name] = Boney M
[rating] = 3
)
[2] = Array
(
[id] = 4
[name] = Lusain
[rating] = 3
)
[3] = Array
(
[id] = 3
[name] = The Killers
[rating] = 4
)
)
array_multisort()函數(shù)是PHP中最有用的函數(shù)之一,它有非常廣泛的應(yīng)用范圍。另外,就如你在例子中所看到的,它能對多個不相關(guān)的數(shù)組進(jìn)行排序,也可以使用其中的一個元素作為下次排序的基礎(chǔ),還可以對數(shù)據(jù)庫結(jié)果集進(jìn)行排序。
這些例子應(yīng)該讓你對PHP中各種數(shù)組排序函數(shù)的使用有了初步的了解,也向你展示了一些隱藏在PHP數(shù)組處理工具包的內(nèi)部功能。
最后,祝你能愉快的使用這些功能!
算法原理
下列動圖來自五分鐘學(xué)算法,演示了快速排序算法的原理和步驟。
步驟:
從數(shù)組中選個基準(zhǔn)值
將數(shù)組中大于基準(zhǔn)值的放同一邊、小于基準(zhǔn)值的放另一邊,基準(zhǔn)值位于中間位置
遞歸的對分列兩邊的數(shù)組再排序
代碼實現(xiàn)
function
quickSort($arr)
{
$len
=
count($arr);
if
($len
=
1)
{
return
$arr;
}
$v
=
$arr[0];
$low
=
$up
=
array();
for
($i
=
1;
$i
$len;
++$i)
{
if
($arr[$i]
$v)
{
$up[]
=
$arr[$i];
}
else
{
$low[]
=
$arr[$i];
}
}
$low
=
quickSort($low);
$up
=
quickSort($up);
return
array_merge($low,
array($v),
$up);
}
測試代碼:
$startTime
=
microtime(1);
$arr
=
range(1,
10);
shuffle($arr);
echo
"before
sort:
",
implode(',
',
$arr),
"\n";
$sortArr
=
quickSort($arr);
echo
"after
sort:
",
implode(',
',
$sortArr),
"\n";
echo
"use
time:
",
microtime(1)
-
$startTime,
"s\n";
測試結(jié)果:
before
sort:
1,
7,
10,
9,
6,
3,
2,
5,
4,
8
after
sort:
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
use
time:
0.0009009838104248s
時間復(fù)雜度
快速排序的時間復(fù)雜度在最壞情況下是O(N2),平均的時間復(fù)雜度是O(N*lgN)。
這句話很好理解:假設(shè)被排序的數(shù)列中有N個數(shù)。遍歷一次的時間復(fù)雜度是O(N),需要遍歷多少次呢?至少lg(N+1)次,最多N次。
1)
為什么最少是lg(N+1)次?快速排序是采用的分治法進(jìn)行遍歷的,我們將它看作一棵二叉樹,它需要遍歷的次數(shù)就是二叉樹的深度,而根據(jù)完全二叉樹的定義,它的深度至少是lg(N+1)。因此,快速排序的遍歷次數(shù)最少是lg(N+1)次。
2)
為什么最多是N次?這個應(yīng)該非常簡單,還是將快速排序看作一棵二叉樹,它的深度最大是N。因此,快讀排序的遍歷次數(shù)最多是N次。
您可能感興趣的文章:PHP快速排序算法實例分析PHP四種排序算法實現(xiàn)及效率分析【冒泡排序,插入排序,選擇排序和快速排序】PHP排序算法之快速排序(Quick
Sort)及其優(yōu)化算法詳解PHP遞歸實現(xiàn)快速排序的方法示例php
二維數(shù)組快速排序算法的實現(xiàn)代碼PHP常用排序算法實例小結(jié)【基本排序,冒泡排序,快速排序,插入排序】PHP快速排序quicksort實例詳解
注:為方便描述,下面的排序全為正序(從小到大排序)
假設(shè)有一個數(shù)組[a,b,c,d]
冒泡排序依次比較相鄰的兩個元素,如果前面的元素大于后面的元素,則兩元素交換位置;否則,位置不變。具體步驟:
1,比較a,b這兩個元素,如果ab,則交換位置,數(shù)組變?yōu)椋篬b,a,c,d]
2,比較a,c這兩個元素,如果ac,則位置不變,數(shù)組變?yōu)椋篬b,a,c,d]
3,比較c,d這兩個元素,如果cd,則交換位置,數(shù)組變?yōu)椋篬b,a,d,c]
完成第一輪比較后,可以發(fā)現(xiàn)最大的數(shù)c已經(jīng)排(冒)在最后面了,接著再進(jìn)行第二輪比較,但第二輪比較不必比較最后一個元素了,因為最后一個元素已經(jīng)是最大的了。
第二輪比較結(jié)束后,第二大的數(shù)也會冒到倒數(shù)第二的位置。
依次類推,再進(jìn)行第三輪,,,
就這樣最大的數(shù)一直往后排(冒),最后完成排序。所以我們稱這種排序算法為冒泡排序。
選擇排序是一種直觀的算法,每一輪會選出列中最小的值,把最小值排到前面。具體步驟如下:
插入排序步驟大致如下:
快速排序是由東尼·霍爾所發(fā)展的一種排序算法。在平均狀況下,排序 n 個項目要Ο(n log n)次比較。在最壞狀況下則需要Ο(n2)次比較,但這種狀況并不常見。事實上,快速排序通常明顯比其他Ο(n log n) 算法更快,因為它的內(nèi)部循環(huán)(inner loop)可以在大部分的架構(gòu)上很有效率地被實現(xiàn)出來,且在大部分真實世界的數(shù)據(jù),可以決定設(shè)計的選擇,減少所需時間的二次方項之可能性。
步驟:
從數(shù)列中挑出一個元素,稱為 “基準(zhǔn)”(pivot),
重新排序數(shù)列,所有元素比基準(zhǔn)值小的擺放在基準(zhǔn)前面,所有元素比基準(zhǔn)值大的擺在基準(zhǔn)的后面(相同的數(shù)可以到任一邊)。在這個分區(qū)退出之后,該基準(zhǔn)就處于數(shù)列的中間位置。這個稱為分區(qū)(partition)操作。
遞歸地(recursive)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序。