- PHP開發手冊
- 孫鵬程等編著
- 5744字
- 2018-12-29 21:30:49
第3章 數組操作與數據結構算法
數組是一個由若干同類型變量組成的集合,引用這些變量時可用同一名字。數組中的每一個變量都叫做數組的一個元素。在開發中,數組有廣泛的用途。本章將對數組及一些數組的使用技巧作詳細講解。
3.1 一維數組與多維數組
數組實際上就是一組變量。數組可以是一維的,也可以是多維的。所謂的多維數組可以理解成元素中包含數組的數組,例如二維數組就是兩個元素個數相同的一維數組構成的。本節將對一維數組與多維數組的定義作一下簡要介紹。
3.1.1 一維數組簡介
一維數組在本質上是由同類數據構成的表,表3-1 說明了一個一維數組$array 鍵與值的對應情形。
表3-1 一維數組

3.1.2 多維數組簡介
PHP允許使用多維數組,最簡單的多維數組是二維數組。實際上,二維數組是以一維數組為元素構成的數組,表3-2說明了一個4×4二維數組$array鍵與值的對應情形。從表中可以看出,每一行都可以看做一個一維數組。4個一維數組按照鍵0、1、2、3的順序又構成了一個新的數組,而這個新的數組就是一個二維數組。
表3-2 二維數組

二維數組有些類似一個普通的二維表。與二維數組和一維數組的關系類似,N維數組可以看做是多個N-1維數組組成的一個新的數組。
3.2 常用的數組操作
數組的一般操作主要包括數組的創建、調用、更新以及數組元素的遍歷等,本節將逐一介紹這些操作。
3.2.1 數組的創建與調用
在PHP中使用array函數來創建一個數組,它接受一定數量用逗號分隔的key => value參數對。其中,key可以是integer或者string,value可以是任何值。以下代碼是一個創建一維數組的例子。
<?php $array = array("key1" => "Simon", 2 => "Elaine"); //數組的創建 echo $array["key1"]; //輸出Simon echo $array[2]; //輸出Elaine ?>
以下代碼是一個創建二維數組的例子。
<?php $array = array("key1" => array(0 => 1, 1 => 10, 2 => 100), "key2" => array(0 => 5, 1 => 25, 2 => 125)); echo $array["key1"][0]; //輸出1 echo $array["key1"][1]; //輸出10 echo $array["key1"][2]; //輸出100 echo $array["key2"][0]; //輸出5 echo $array["key2"][1]; //輸出25 echo $array["key2"][2]; //輸出125 ?>
上面的例子通過列舉數組中每一個元素的方法輸出數組。但是,當數組中元素很多的時候,使用這種方法就顯得過于麻煩了。通常在程序中使用循環語句 foreach 來輸出數組的每一個元素,關于foreach 的具體用法,本節會在后面詳細介紹。對于以調試為目的的輸出,還有一個簡單的方法,就是使用print_r函數直接輸出數組內容。將上面的例子修改后如下所示。
<?php $array = array("key1" => array(0 => 1, 1 => 10, 2 => 100), //定義數組 "key2" => array(0 => 5, 1 => 25, 2 => 125)); print_r($array); //輸出數組 ?>
代碼運行結果如下。
Array ( [key1] => Array ( [0] => 1 [1] => 10 [2] => 100 ) [key2] => Array ( [0] => 5 [1] => 25 [2] => 125 ) )
由以上代碼可以看出,這種簡單的方法可以輸出數組的完整內容和結構。在代碼調試的過程中,這種用法非常常見。但是,這種方法的輸出不夠美觀,所以,在實際應用中往往不使用。
如上所示,二維數組實際上就是值為一維數組的數組。以此類推,可以創建其他類型的多維數組。此處不再舉例說明。
在實際應用中,往往不明確地指定鍵名,PHP會從0開始依次自動分配鍵名,代碼如下。
<?php $array = array("a", "b","c"); //定義數組 print_r($array); //輸出數組 ?>
代碼運行結果如下。
Array ( [0] => a [1] => b [2] => c )
由以上結果可以看出,數組的鍵名被自動分配了。
3.2.2 數組的更新
前面的例子中包括了對數組中元素的調用,數組創建以后,對數組中元素的調用是通過方括號([])的方式進行的。同樣,對數組元素進行更新也是通過方括號([])的方式進行的。通常,通過在方括號內指定鍵名,并明確地設定一個新值賦值給數組,以此來改變一個現有的數組,代碼如下。
<?php $array = array("a", "b","c"); //定義數組 $array[0] = "Simon"; //修改數組元素 print_r($array); //輸出數組 ?>
代碼運行結果如下。
Array ( [0] => Simon [1] => b [2] => c )
上面的程序通過對$array[0]的重新賦值實現了對數組元素的更新。
3.2.3 數組元素的遍歷
在上面對數組元素進行逐一釋放的例子中,使用了foreach函數。foreach函數是PHP提供的一種遍歷數組的簡便方法。foreach僅能用于數組,將其用于其他數據類型或者一個未初始化的變量時會產生錯誤。具體有兩種語法格式,如下所示。第二種比較次要,但卻是第一種的有效擴展。
foreach (array as $value) statements foreach (array as $key => $value) statements
第一種格式遍歷給定的array數組。每次循環中,當前單元的值被賦給$value,并且數組內部的指針向前移一步。第二種格式做同樣的事,只是當前單元的鍵值也會在每次循環中被賦給變量$key。以下代碼使用了這兩種方法對一個一維數組進行遍歷。
<?php //定義一個數組 $arr = array(0=>"zero", 1=>"one", 2=>"two"); //使用第一種方法對數組進行遍歷 foreach ($arr as $value) { echo "Value: $value; "; } echo "<BR>"; //使用第二種方法對數組進行遍歷 foreach ($arr as $key => $value) { echo "Key: $key; Value: $value; "; } ?>
代碼運行結果如下。
Value: zero; Value: one; Value: two; Key: 0; Value: zero; Key: 1; Value: one; Key: 2; Value: two;
對多維數組的遍歷,只需要嵌套使用 foreach 結構即可。以下代碼對一個二維數組進行遍歷。
<?php //定義數組 $array = array("ar1" => array(5=>100, 3=>120, 4=>30), "ar2" => array(4=>"three", 9=>"four", 1=>"five")); //對數組進行遍歷 foreach ($array as $v1) { foreach ($v1 as $v2) { print "$v2\n"; } } ?>
代碼運行結果如下。
100 120 30 three four five
3.3 數組索引與鍵值的操作技巧
所謂索引,就是數組鍵名的集合。在數組創建的時候,數組的索引也會被隨之建立。如上面講述的那樣,如果沒有指定鍵名,PHP會自動分配鍵名,這就是索引起了作用。
除了在創建數組時可以省略鍵名,在更新數組的時候也可以省略鍵名,也就是只給數組名加上一對空的方括號。使用省略鍵名方式增加新的鍵,新的鍵名會使用最大整數鍵名加1,代碼如下所示。
<?php $array = array("a", "b","c"); //定義數組 $array[] = "Simon"; //增加一個新的數組元素 print_r($array); //輸出數組 ?>
代碼運行結果如下。
Array ( [0] => a [1] => b [2] => c [3] => Simon )
在更新數組時,如果指定的鍵名不存在,則會新建一個鍵,如以下代碼所示。
<?php $array = array("a", "b","c"); //定義數組 $array[9] = "Simon"; //增加一個新的數組元素 print_r($array); //輸出數組 ?>
運行結果如下所示。
Array ( [0] => a [1] => b [2] => c [9] => Simon )
如果要刪除一個鍵名,可以使用unset函數進行釋放。unset函數應用于數組有兩種使用方法,一種是刪除整個數組,另一種是保持數組結構而逐一刪除鍵。如果使用 unset 函數對數組中的每個元素進行逐一釋放而保持數組結構,使用省略鍵名方式增加新的鍵時,新的鍵名依然會使用最大整數鍵名加1。如果希望對數組進行重新索引,則需要使用array_values 函數。以下代碼是一個更新數組的例子。
<?php //創建一個簡單的數組 $array = array(0=>1, 1=>2, 2=>3, 3=>4, 6=>5); print_r($array); //現在把數組中鍵為2的值更新為100 $array[2] = 100; print_r($array); //現在添加一個鍵 $array["X"] = 50; print_r($array); //現在刪除所有鍵,但保持數組本身的結構 foreach($array as $i => $value) { unset($array[$i]); } print_r($array); //再添加一個鍵 $array[] = 25; print_r($array); //使用array_values函數進行重新索引 $array = array_values($array); $array[] = 13; print_r($array); ?>
代碼運行結果如下所示。
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [6] => 5 ) Array ( [0] => 1 [1] => 2 [2] => 100 [3] => 4 [6] => 5 ) Array ( [0] => 1 [1] => 2 [2] => 100 [3] => 4 [6] => 5 [X] => 50 ) Array ( ) Array ( [7] => 25 ) Array ( [0] => 25 [1] => 13 )
3.4 數組的排序
在PHP數組函數庫中,提供了多種對數組元素進行排序的函數。本節主要介紹其中最常用的3種,即sort函數、rsort函數和array_multisort函數。
3.4.1 遞增排序——sort
sort 函數對數組中的值進行排序。當函數結束時數組單元將被從最低到最高重新安排,該函數的語法格式如下所示。
void sort(array array [, int sort_flags])
其中array是要排序的數組,sort_flags表示排序行為,包括以下幾種。
? SORT_REGULAR:正常比較單元。
? SORT_NUMERIC:單元被作為數字來比較。
? SORT_STRING:單元被作為字符串來比較。
以下代碼應用sort函數實現了對一個數組的排序。
<?php $arr = array(5=>"zero", 3=>"one", 4=>"two"); //定義一個數組 sort($arr); //使用sort對數組進行排序 foreach ($arr as $key => $value) //對數組進行遍歷查看排序后的結果 { echo "Key: $key; Value: $value; "; } ?>
代碼運行結果如下。
Key: 0; Value: one; Key: 1; Value: two; Key: 2; Value: zero;
需要注意的是,數組在被排序后鍵被重新分配了。排序函數是對數組的值進行排序,在這個例子中,就是對zero、one和two 3個字符串進行排序,按照字母的順序排序結果為one、two和zero。
3.4.2 遞減排序——rsort
與sort函數相反,rsort函數對數組進行逆向排序(從最高到最低),該函數的語法如下所示。
void rsort(array array [, int sort_flags])
其中的參數含義與sort函數完全相同。以下代碼使用rsort函數修改了上面的例子。
<?php //定義一個數組 $arr = array(5=>"zero", 3=>"one", 4=>"two"); //使用rsort對數組進行排序 rsort($arr); //對數組進行遍歷查看排序后的結果 foreach ($arr as $key => $value) { echo "Key: $key; Value: $value; "; } ?>
運行結果如下所示。
Key: 0; Value: zero; Key: 1; Value: two; Key: 2; Value: one;
從這里可以看出,使用rsort函數的排序結果與sort函數完全相反。但是,與sort函數相同,鍵值被重新分配了。
3.4.3 數組排序——array_multisort
array_multisort函數用于對多個數組或多維數組進行排序。使用array_multisort函數可以一次對多個數組進行排序或者根據某一維對多維數組進行排序。與sort函數和rsort函數不同的是 array_multisort 函數排序時保留原有的鍵名關聯,即數組的鍵不會被重新分配,該函數的語法格式如下所示。
bool array_multisort(array array [,arg [,sort_flags ... [, array ...]]])
其中,array是要被排序的數組,arg表示排序順序標志,包括以下幾種。
? SORT_ASC:按照從最低到最高順序排序(默認);
? SORT_DESC:按照從最高到最低順序排序。
sort_flags表示排序行為,包括以下幾種。
? SORT_REGULAR:正常比較單元(默認)。
? SORT_NUMERIC:單元被作為數字來比較。
? SORT_STRING:單元被作為字符串來比較。
以下代碼是一個對多個數組進行排序的例子。
<?php //定義2個數組 $ar1 = array(5=>"zero", 3=>"one", 4=>"two"); $ar2 = array(4=>"three", 9=>"four", 1=>"five"); //對數組進行排序 array_multisort($ar1, $ar2); //對數組進行遍歷查看排序后的結果 foreach ($ar1 as $key => $value) { echo "Key: $key; Value: $value; "; } echo "<BR>"; foreach ($ar2 as $key => $value) { echo "Key: $key; Value: $value; "; } ?>
代碼運行結果如下。
Key: 0; Value: one; Key: 1; Value: two; Key: 2; Value: zero; Key: 0; Value: four; Key: 1; Value: five; Key: 2; Value: three;
以下代碼是一個對多維數組進行排序的例子。
<?php //定義一個二維數組 $array = array("ar1" => array(5=>100, 3=>120, 4=>30), "ar2" => array(4=>"three", 9=>"four", 1=>"five")); //對數組進行排序 array_multisort($array["ar1"], SORT_NUMERIC, SORT_DESC, $array["ar2"], SORT_STRING, SORT_ASC); //對數組進行遍歷查看排序后的結果 foreach ($array as $v1) { foreach ($v1 as $v2) { echo "$v2\n"; } } ?>
代碼運行結果如下。
120 100 30 four three five
3.5 幾種數組的應用實例
數組的一個重要應用就是對數據結構算法的實現。本節將以幾個常見的例子來說明如何使用PHP來實現這些應用。
3.5.1 順序查找
順序查找是在數組中查找某個元素的最簡便方法,即通過對數組元素的逐一比較來得到結果。以下代碼中的函數search即完成了這項操作。如果找到要找的值,則結果為該值所在的鍵。如果沒有找到,則返回-1。
<?php function search($array, $k) //search函數,$array為數組,$k為要查找的值 { $n = count($array); //count函數用于計算數組中的元素個數 $array[$n] = $k; //新建一個元素,并將k存放進去 for($i=0; $i<$n; $i++) //逐一比較 { if($array[$i]==$k) { break; } } if ($i<$n) //如果在新元素的前面找到了要找的值,則返回該值 { return $i; } else //否則,返回-1 { return -1; } } $array = array(5,6,3); //測試search函數 echo search($array, 6); //調用search函數并輸出查找結果 ?>
上面程序的運行結果為1,也就是在數組$array中找到了值為6的元素,鍵名為1。
3.5.2 二分法查找
二分法查找是在數組中查找某個元素的一種效率較高的方法。但是二分法查找需假定數組已經是排好序的,然后通過對數組元素的比較來得到結果。每次不成功的比較都會排除掉一半的數組元素。以下代碼中的函數search即實現了這個算法。如果找到要找的值,則結果為該值所在的鍵。如果沒有找到,則返回-1。
<?php //search函數 其中$array為數組,$k為要找的值,$low為查找范圍的最小鍵值,$high為查找范圍的最大鍵值 function search($array, $k, $low=0, $high=0) { if(count($array)!=0 and $high == 0) //判斷是否為第一次調用 { $high = count($array); } if($low <= $high) //如果還存在剩余的數組元素 { $mid = intval(($low+$high)/2); //取$low和$high的中間值 if ($array[$mid] == $k) //如果找到則返回 { return $mid; } elseif ($k < $array[$mid]) //如果沒有找到,則繼續查找 { return search($array, $k, $low, $mid-1); } else { return search($array, $k, $mid+1, $high); } } return -1; } $array = array(4,5,7,8,9,10); //測試search函數 echo search($array, 8); //調用search函數并輸出查找結果 ?>
這里需要注意在函數search中對search函數進行的遞歸調用。
3.5.3 使用array_search函數進行查找
除了可以使用前面介紹的方法對數組元素進行查找外,還可以使用 PHP 自帶的array_search函數進行查找,其語法如下所示。
array_search(value, array)
其中value是要查找的值,array是要查找的數組。該函數如果在數組中找到了值,則返回該值所在的鍵,如果沒有找到,則返回FALSE。以下代碼是使用array_search進行查找的例子。
<?php $array = array(4,5,7,8,9,10); $found = array_search(8, $array); //調用array_search函數并輸出查找結果 if($found) //如果找到輸出鍵 echo "已找到,鍵為".$found; else //如果沒有找到輸出錯誤信息 echo "沒有找到"; ?>
代碼輸出結果如下。
已找到,鍵為3
由以上代碼可以看出,array_search函數的作用與前面介紹的查找功能相同。
3.5.4 線性表的入棧與出棧
前面介紹了如何對數組中的元素進行插入和刪除。在數據結構中,常常有入棧與出棧的例子。入棧即將更多的元素壓入數組并放置到數組的最后。出棧即將數組的最后一個元素刪除掉。
1.入棧
PHP中,入棧通過函數array_push來實現,其語法格式如下所示。
int array_push(array, var [, var ...])
var即要壓入數組的元素,array為數組。函數將返回數組新的元素總數。以下代碼是一個入棧的例子。
<?php $stack = array("Simon", "Elaine"); //定義數組 array_push($stack, "Helen", "Peter"); //入棧 print_r($stack); ?>
代碼運行結果如下。
Array ( [0] => Simon [1] => Elaine [2] => Helen [3] => Peter )
可以看到,兩個新元素被追加到了數組$array 的最后。除了可以將新元素從數組的末尾追加以外,還可以從數組的第一個元素前追加。這時需要使用函數 array_unshift 來完成。array_unshift 函數的使用方法與 array_push 類似,以下代碼改寫了上面的例子,使用array_unshift來代替array_push。
<?php $stack = array("Simon", "Elaine"); //定義數組 array_unshift ($stack, "Helen", "Peter"); //入棧 print_r($stack); ?>
代碼運行結果如下。
Array ( [0] => Helen [1] => Peter [2] => Simon [3] => Elaine )
由以上代碼可以看到,兩個新元素被追加到了數組$array的最前面。
2.出棧
PHP中,出棧通過函數array_pop來實現,其語法格式如下所示。
array_push(array)
array為數組。函數將返回數組的最后一個元素,即被刪除的元素。以下代碼是一個出棧的例子。
<?php $stack = array("Simon", "Elaine", "Helen", "Peter"); echo array_pop($stack)."\n"; //出棧 print_r($stack); ?>
運行結果如下所示。
Peter Array ( [0] => Simon [1] => Elaine [2] => Helen )
由以上代碼可以看到,最后的一個元素已經從數組$array 中被刪除了,而被刪除的元素的值也被成功地輸出到了屏幕上。
與array_push和array_unshift的關系類似,對于array_pop函數也有一個對應的用于從數組前端出棧的函數。該函數是array_shift,用法與array_pop類似。以下代碼改寫了上面的例子。
<?php $stack = array("Simon", "Elaine", "Helen", "Peter"); echo array_shift($stack)."\n"; //出棧 print_r($stack); ?>
運行結果如下所示。
Simon Array ( [0] => Elaine [1] => Helen [2] => Peter )
由以上代碼可以看到,第一個元素已經從數組$array 中被刪除了,而被刪除的元素的值也被成功地輸出到了屏幕上。
3.5.5 數組的合并
array_merge函數用于數組的合并操作,其語法格式如下所示。
array_merge(array1, array2, …)
該函數用于將參數中的數組合并到一個新數組中。以下代碼是一個合并數組的例子。
<?php $array1 = array("A","B","C","D"); $array2 = array("1","2","3","4"); $array3 = array("!","@","#","$"); $arrayX = array_merge($array1, $array2, $array3); //將3個數組合并起來 print_r($arrayX); ?>
該函數的輸出結果如下所示。
Array ( [0] => A [1] => B [2] => C [3] => D [4] => 1 [5] => 2 [6] => 3 [7] => 4 [8] => ! [9] => @ [10] => # [11] => $ )
如果前面的例子在數組定義的時候指定了鍵名,則在合并時如果鍵名有重復會出現問題。例如,以下代碼就沒有得到預期的結果。
<?php $array1 = array("AA"=>"A","BB"=>"B","CC"=>"C","DD"=>"D"); $array2 = array("AA"=>"1","BB"=>"2","CC"=>"3","DD"=>"4"); $array3 = array("AA"=>"!","BB"=>"@","CC"=>"#","DD"=>"$"); $arrayX = array_merge($array1, $array2, $array3); //合并數組 print_r($arrayX); ?>
代碼運行結果如下。
Array ( [AA] => ! [BB] => @ [CC] => # [DD] => $ )
由以上結果可以看出,只有array3中的元素被保存了下來。為此,PHP還提供了一種合并數組的方式,即 array_merge_recursive 函數。該函數可以將鍵名相同的元素放置到一個數組中。例如,以下代碼使用array_merge_recursive函數改寫了上面的例子。
<?php $array1 = array("AA"=>"A","BB"=>"B","CC"=>"C","DD"=>"D"); $array2 = array("AA"=>"1","BB"=>"2","CC"=>"3","DD"=>"4"); $array3 = array("AA"=>"!","BB"=>"@","CC"=>"#","DD"=>"$"); $arrayX = array_merge_recursive($array1, $array2, $array3); //合并數組 print_r($arrayX); ?>
運行結果如下所示。
Array ( [AA] => Array ( [0] => A [1] => 1 [2] => ! ) [BB] => Array ( [0] => B [1] => 2 [2] => @ ) [CC] => Array ( [0] => C [1] => 3 [2] => # ) [DD] => Array ( [0] => D [1] => 4 [2] => $ ) )
3.5.6 數組的拆分
前面介紹了數組的合并,PHP除了提供數組的合并方法以外,還提供了數組的拆分方法。在介紹拆分數組的方法之前首先介紹一下取數組子集的方法。array_slice 函數用于取數組的子集,語法格式如下所示。
array_slice(array, int start [, int length])
這里,array是原數組,start是子集的開始位置,length是子集的長度。如果不指定length,則表示一直取到數組的末尾。以下代碼是一個使用array_slice獲取數組子集的例子。
<?php $array = array(1,2,3,4,5,6,7,8,9); $arrayX = array_slice($array, 2, 6); //獲取數組的第2個到第7個元素 print_r($array); print_r($arrayX); ?>
代碼運行結果如下。
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 [6] => 7 [7] => 8 [8] => 9 ) Array ( [0] => 3 [1] => 4 [2] => 5 [3] => 6 [4] => 7 [5] => 8 )
由以上結果可以看到,數組的子集被取了出來,而且并不影響原數組。PHP提供了一種真正達到拆分數組的函數——array_splice函數。該函數與array_slice用法完全相同,不同的是其結果會將取出的元素從原數組中刪除。以下代碼改寫了上面的例子。
<?php $array = array(1,2,3,4,5,6,7,8,9); $arrayX = array_splice($array, 2, 6); //獲取數組的第2個到第7個元素 print_r($array); print_r($arrayX); ?>
代碼運行結果如下。
Array ( [0] => 1 [1] => 2 [2] => 9 ) Array ( [0] => 3 [1] => 4 [2] => 5 [3] => 6 [4] => 7 [5] => 8 )
由以上結果可以看出,被取出的元素已經被從原數組中刪除了。
3.5.7 隨機排序
PHP還提供了一個很有用的函數,類似于撲克游戲中的洗牌。函數shuffle可以隨機地將數組打亂,得到一個元素與原數組內容相同、順序不同的新數組,其語法格式如下所示。
void shuffle(array)
以下代碼演示了這個函數的使用方法。
<?php $array = array('A','2','3','4','5','6','7','8','9','10','J','Q','K'); shuffle($array); //隨機排序數組 print_r($array); //輸出數組 ?>
代碼運行結果如下。
Array ( [0] => 2 [1] => 4 [2] => 8 [3] => A [4] => 9 [5] => 3 [6] => Q [7] => J [8] => 10 [9] => 6 [10] => K [11] => 5 [12] => 7 )
由以上結果可以看出,數組$array 已經被打亂了。需要注意的是這個運行結果不是絕對的,因為shuffle函數是隨機打亂的機制,所以每次運行其結果可能都不相同。
3.6 小結
本章介紹了PHP中數組的基本應用。在實際應用中,數組通常用于存放一組元素數據。例如,在訂閱系統中用戶提交的訂閱清單等。本章中常用的數組操作是重點,這些操作會在實際應用中經常被用到。讀者也可以結合數組索引進行一些常用的數組操作。
數組與數據結構算法的結合是本章的一個難點。但是,往往不通過類似PHP這種腳本語言來實現一些復雜的算法運算,在實際的Web應用中,復雜的算法也不多見。因此,對于一些復雜的算法操作,不建議讀者使用PHP來實現。