PHP資料結構(五) ——陣列的壓縮與轉置
PHP資料結構(五)——陣列的壓縮與轉置
(原創內容,轉載請註明來源,謝謝)
1、陣列可以看作是多個線性表組成的資料結構,二維陣列可以有兩種儲存方式:一種是以行為主序,另一種是以列為主序。
2、當陣列存在特殊情況時,為了節省儲存空間,可以進行壓縮儲存,把相同值並有規律分佈的元素只分配一個儲存空間,對於零元素不進行儲存。
有兩種情況可以進行壓縮儲存——特殊矩陣與稀疏矩陣。
3、當陣列為特殊的矩陣,例如陣列為n階對稱矩陣(滿足aij=aji)。對於該型別矩陣,可以只儲存一半的數值加上對角線的內容,一共需要分配n*(n+1)/2的儲存空間。同時,上(下)三角矩陣也可以用此方式進行儲存。(三角矩陣為一半有值,另一半值為0的矩陣)
儲存N階對稱矩陣的方式,即以對稱對角線為分界,僅取其中一半的內容以及對角線進行儲存。
PHP壓縮與還原n階對稱矩陣的原始碼如下:
<?php //儲存n階對稱矩陣 function symmetricMatrixSave($n,$arr){ $arrResult= array(); $k= 0;//結果陣列的下標 for($i=0;$i<$n;$i++){ for($j=0;$j<=$i; $j++){ $arrResult[$k++]= $arr[$i][$j]; } } return$arrResult; } //還原n階對稱矩陣 function symmetricMatrixRe($arr){ $rank= $arr[0]; $arrResult= array(); $row= 0; $col= 0; for($k=0;$k<count($arr); $k++){ //根據取出的值還原半邊 $arrResult[$row][$col]= $arr[$k]; //根據對稱性還原另一半 $arrResult[$col][$row]= $arrResult[$row][$col]; $col++; //根據儲存規則,只存一半的值,因此col不會大於row if($col> $row){ $col= 0; $row++; } } return$arrResult; } //呼叫n階矩陣的儲存還原 $arr = array( 0=> array(0, 1, 2, 3), 1=> array(1, 2, 3, 4), 2=> array(2, 3, 4, 5), 3=> array(3, 4, 5, 6) ); print_r($arr); //列印原陣列Array ( [0]=> Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 ) [1] => Array( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) [2] => Array ( [0] =>2 [1] => 3 [2] => 4 [3] => 5 ) [3] => Array ( [0] => 3 [1] =>4 [2] => 5 [3] => 6 ) ) echo '<br />'; $arrResult = symmetricMatrixSave(4, $arr); print_r($arrResult); //壓縮後的結果Array ( [0]=> 0 [1] => 1 [2] => 2 [3] => 2 [4] => 3 [5] => 4 [6] => 3[7] => 4 [8] => 5 [9] => 6 ) echo '<br />'; $arrRe = symmetricMatrixRe($arrResult); print_r($arrRe); //還原後的結果,與壓縮前相同Array ([0] => Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 ) [1] =>Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) [2] => Array ( [0]=> 2 [1] => 3 [2] => 4 [3] => 5 ) [3] => Array ( [0] => 3 [1]=> 4 [2] => 5 [3] => 6 ) )
4、當矩陣為稀疏矩陣,即在m*n的矩陣中,有t個不為0的元素,且滿足t/(m*n)<=0.5。稀疏矩陣通常用三元陣列進行儲存,(i,j,value)分別表示不為零的元素的行、列以及值。
除了上述的三元陣列的壓縮方式,稀疏矩陣還有兩種壓縮方式。分別是行邏輯連結的順序表、十字連結串列。
4.1 三元組順序表
三元組順序表以行為主序,以列為次序,從小到大進行排列。例如:[(0,1,30),(0,3,50),(1,2,18),(3,5,20)],表示該稀疏矩陣共有四個非零元素,分別在(0,1)、(0,3)、(1,2)、(3,5)四個位置,值分別是30、50、18、20。
該方法儲存的表,要進行轉置操作非常便利。轉置需要進行三步操作,分別是:行列的值進行轉換、i和j進行轉換、重新從小到大排列i和j。因此,轉置的重點在於最後一步——排序。
對於排序,可以通過從0開始掃描原陣列的列,並將結果相應放入新陣列的行。也可以採用下述的快速轉置法。
快速轉置陣列演算法:
假設原矩陣為M,新矩陣為T,引入兩個新的陣列,陣列num[col]為第col列非零元的個數,cpot[col]為第col列第一個非零元在新矩陣T生成的三元組順序表的位置。在轉置前,先通過原矩陣M獲取這兩個陣列,用於快速轉換的計算。
PHP快速轉置稀疏矩陣的原始碼如下:
<?php
//快速轉置稀疏矩陣
//根據原標準三元陣列獲取每一列非零元個數及第一個非零元的位置
/* 輸入要求
array(
0=>array(0,1,33),
1=>array(0,5,67),
2=>array(1,2,66),
3=>array(3,4,55)
)*/
function getAuxiliaryArray($arr){
$num= array();//每一列非零元個數
foreach($arras $key => $val){
$num[next($val)]++;//next($val)獲取列值
}
ksort($num);//根據鍵對陣列升序排列
$row_position= 0;
$cpot= array();
foreach($numas $key => $val){
$cpot[$key]= $row_position;
$row_position= $row_position + $val;
}
returnarray('num'=>$num, 'cpot'=>$cpot);
}
//轉置方法
function getReverse($arr, $num, $cpot){
$arrResult= array();
foreach($arras $key => $val){
$row= current($val);
$col= next($val);
$val= next($val);
$arrResult[$cpot[$col]]= array($col, $row, $val);
$cpot[$col]++;//用於存放同一列下一個值的位置
}
return$arrResult;
}
$arrPrev = array(
0=>array(0,1,33),
1=>array(0,5,67),
2=>array(1,2,66),
3=>array(2,2,69),
4=>array(3,4,55)
);
$arrTemp = getAuxiliaryArray($arrPrev);
$arrAfter = getReverse($arrPrev,$arrTemp['num'], $arrTemp['cpot']);
print_r($arrAfter);
//輸出Array ( [0] =>Array ( [0] => 1 [1] => 0 [2] => 33 ) [1] => Array ( [0] => 2[1] => 1 [2] => 66 ) [2] => Array ( [0] => 2 [1] => 2 [2] =>69 ) [3] => Array ( [0] => 4 [1] => 3 [2] => 55 ) [4] => Array ([0] => 5 [1] => 0 [2] => 67 ))
——written by linhxx 2017.06.23
相關閱讀: