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

相关阅读:

PHP数据结构(四) ——队列

PHP数据结构(三)——运用栈实现括号匹配

PHP数据结构(二)——链式结构线性表

PHP数据结构(一)——顺序结构线性表

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-06-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hbbliyong

看到他我一下子就悟了-- Lambda表达式

一直对Lambda表达式似懂非懂,平常也用过,就是不太明白有时候还要百度。周六去图书馆看书,看到下面这几句话,一下子就悟了: Lambda表达式(匿名函数),基...

2756
来自专栏前端说吧

JS-几大排序算法(更新中...)

3085
来自专栏Petrichor的专栏

numpy: 常用api速查

1087
来自专栏我分享我快乐

响应式jquery小效果实现思路

有很多同学在实现jquery效果时,不知道怎样符合响应式布局。我写了个小案例,帮大家找找思路,希望能帮到你。 效果如下: ? 代码如下: <!doct...

35711
来自专栏Python攻城狮

科学计算工具Numpy1.ndarray的创建与数据类型2.ndarray的矩阵运算ndarray的索引与切片3.ndarray的元素处理元素判断函数元素去重排序函数4.2016年美国总统大选民意调查

Numpy:提供了一个在Python中做科学计算的基础库,重在数值计算,主要用于多维数组(矩阵)处理的库。用来存储和处理大型矩阵,比Python自身的嵌套列表结...

813
来自专栏抠抠空间

python常见模块之random模块

python常见模块之random模块 import random print(random.random()) #随机产生一个0-1之间的小数 p...

26410
来自专栏TensorFlow从0到N

讨厌算法的程序员 7 - 归并排序的时间复杂度分析

? 递归树 上一篇归并排序基于分治思想通过递归的调用自身完成了排序,本篇是关于归并排序的最后一部分——分析其时间复杂度。 这个过程中会解释清楚在各种时间复杂度...

2346
来自专栏Python小屋

Python标准库random用法精要

random标准库主要提供了伪随机数生成函数和相关的类,同时也提供了SystemRandom类(也可以直接使用os.urandom()函数)来支持生成加密级别要...

2746

在Python机器学习中如何索引、切片和重塑NumPy数组

在Python中,数据几乎被普遍表示为NumPy数组。

4229
来自专栏ACM算法日常

递归算法复杂度Ω分析-分享

1. 深入认识递归 (1) 递归执行过程 例子:求N!。 这是一个简单的"累乘"问题,用递归算法也能解决。 n! ...

371

扫码关注云+社区