PHP資料結構(六) ——陣列的相乘、廣義表
PHP資料結構(六)——陣列的相乘、廣義表
(原創內容,轉載請註明來源,謝謝)
本文接PHP資料結構(五)的內容。
4.2 行邏輯連結的順序表
行邏輯連結的順序表,即在上述三元表的基礎上,附加一個數組,用於儲存每一行第一個非零元的位置。
該儲存方式,主要是便於對兩個稀疏矩陣進行乘法操作。
矩陣M(a行b列)和N(b行c列)相乘(m的行必須等於n的列),結果是一個a行c列的矩陣。
根據矩陣乘法的方式,計算步驟如下:
1、矩陣M的第a’行b‘列(0<=a’<=a,0<=b’<=b)的值(非零元),只需要和矩陣N的第b‘行的每個非零元所在的列col’相乘,作為第col‘列的暫存的值。
2、遍歷M的第a’行的非零元,分別進行上述操作,並把暫存的值進行相加。
3、遍歷完所有M的非零元,即完成乘法操作。
現假設兩個稀疏矩陣如下:
M=array(
0=>array(0,1,25), 1=>array(1,3,15), 2=>array(2,2, 10), 3=>array(3,1,15)
);
N=array(
0=>array(0,3,10), 1=>array(1,4,15),2=>array(2,3,20), 3=>array(3,3,30)
);
PHP計算稀疏矩陣乘法原始碼如下:
//稀疏矩陣乘法 //獲取每一行的非零值 functiongetNotZeroRowPosi($arr){ $arrResult = array(); $row = 0; $pos = 0; foreach($arr as $key => $val){ $tmpRow = current($val); if($tmpRow == $row){ if(!isset($arrResult[$row])){//考慮到第一次迴圈的時候的初始值 $arrResult[$row]= $pos; } $pos++;//計算本行佔據的空間 }else{ $row = $tmpRow; $arrResult[$row] =$pos++; } } return $arrResult; } //乘法 functionmutiArray($arr1, $arr2){ $rowPosi2 = getNotZeroRowPosi($arr2); $arrResult = array(); foreach($arr1 as $key => $val){//遍歷第一個矩陣 $row1 = current($val); $col1 = next($val); $value1 = next($val); for($i=$rowPosi2[$col1];;$i++){ if(!isset($arr2[$i])){//矩陣2取完後彈出 break; } $tmpArr = $arr2[$i];//取出矩陣2的第i行的非零元開始陣列 $row2 =current($tmpArr); if($row2 != $col1){ break;//迴圈結束矩陣2的第i行後,退出此迴圈 } $col2 =next($tmpArr); $value2 =next($tmpArr); $value =$value1*$value2; if(!isset($arrResult[$row1][$col2])){ $arrResult[$row1][$col2]= $value; }else{ $arrResult[$row1][$col2]+= $value; } } } return $arrResult; } //呼叫乘法函式 $arrPrev =array( 0=> array(0,1,25),1=>array(1,3,15), 2=>array(2,2, 10), 3=>array(3,1,15) ); $arrLast =array( 0=>array(0,3,10), 1=>array(1,4,15),2=>array(2,3,20), 3=>array(3,3,30) ); $arrResult =mutiArray($arrPrev, $arrLast); print_r($arrResult); //計算結果Array ([0] => Array ( [4] => 375 ) [1] => Array ( [3] => 450 ) [2] =>Array ( [3] => 200 ) [3] => Array ( [4] => 225 ) )
4.3 十字連結串列
十字連結串列主要用於稀疏矩陣相加的情況較多時的壓縮儲存方式。其與連結串列非常相似,但是有兩個next指標,一個指向本行的下一個非零元(如果沒有就指向null),另一個指向本列下一個非零元(如果沒有就指向null)。
另外,需要設定兩個頭指標陣列,一個指向每一列的第一個非零元,另一個指向每一行的第一個非零元。
矩陣相加的方式:
1、當矩陣M和矩陣N相加時,如果矩陣N的第(i,j)個位置M矩陣沒有值,那麼就在十字連結串列中插入此節點。
2、將插入後的節點的next指標分別指向本行、本列的下一個節點,如果沒有下一個節點指向null。
3、改變該節點的上方與左方的節點的next指標指向新插入的節點,如果沒有上方或左方的節點,則由相應的頭指標陣列指向該節點。
4、如果矩陣N的第(i,j)個位置M矩陣有值,且M和N該值相加不等於0(因為考慮到正數加負數等同於減的情況),則只需要改變該節點的值,不需要變換指標。
5、如果矩陣N的第(i,j)個位置M矩陣有值,且M和N該值相加等於0,則需要刪除此節點。操作方式為將該節點的上方的節點(包括頭節點)的next指向該節點的下一個節點(沒有則指向null),將該節點的左邊的節點(包括頭節點)的next指向該節點的右邊的節點(沒有則指向null)。
5、廣義表
5.1 廣義表表示為LS=(a1,a2,…an),其中的任意ai(1<=i<=n)可以是單個原子,如數字、字串,也可以是廣義表。即廣義表是可以巢狀的。需要注意的是,’’與array()不一樣,’’表示單個原子空值,array()表示沒有元素的廣義表。
5.2 廣義表的深度即廣義表中巢狀最多的層級數。
5.3 廣義表通過鏈式結構儲存,有兩種儲存方式。
方法一:
方法二:
5.4 根據廣義表,可以做出遞迴演算法。運用遞迴演算法,可以算出廣義表的深度。
廣義表深度的計算方式,即遍歷廣義表的每一個ai,如果ai也是廣義表,則進一步遍歷ai的下一層。
廣義表每一層的深度即為下一層深度的值加1,原子的深度為0,空表的深度為1。由此,可以計算廣義表的深度。
PHP計算廣義表的原始碼如下:
//計算廣義表的深度
function getDeepthArr($arr){
$curMaxDeep= 0;
foreach($arras $item){
if(!is_array($item)){
continue;
}else{
$deep= getDeepthArr($item);
if($deep > $curMaxDeep){
$curMaxDeep= $deep;
}
}
}
return$curMaxDeep+1;
}
$arr = array(array('a'), 1,array(array('a', array(array()), '')), 'a');
$deep = getDeepthArr($arr);
echo $deep;//結果為5
——written by linhxx 2017.06.23
相關閱讀: