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 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

Tensorflow教程: tf.Variable() 和tf.get_variable()

1、使用tf.Variable时,如果检测到命名冲突,系统会自己处理。使用tf.get_variable()时,系统不会处理冲突,而会报错

14030
来自专栏Python小屋

Python花式编程案例锦集(3)

严格来说,本文的2个代码不算花式编程,在Python中就应该是这样写。 1、生成包含20个随机数的列表,然后删除其中的所有奇数。 from random imp...

371130
来自专栏人工智能

如何为机器学习索引,切片,调整 NumPy 数组

具体在 Python 中,数据几乎被都被表示为 NumPy 数组。

75970
来自专栏数据结构与算法

LOJ #108. 多项式乘法

内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 这是一道...

36980
来自专栏数据结构与算法

洛谷 P1313 计算系数

题目描述 给定一个多项式 ,请求出多项式展开后 项的系数。 输入输出格式 输入格式: 输入文件名为factor.in。 共一行,包含5 个整数,分别为 a...

32730
来自专栏算法修养

单调队列,单调栈总结

最近几天接触了单调队列,还接触了单调栈,就总结一下。 其实单调队列,和单调栈都是差不多的数据类型,顾名思义就是在栈和队列上加上单调,单调递增或者单调递减。当...

61580
来自专栏书山有路勤为径

C++ vectors

现在,向量声明,cout和endl不再需要std ::,这让你的程序知道你的意思是标准库中的cout函

10830
来自专栏数据小魔方

左手用R右手Python系列8——数据去重与缺失值处理

因为最近事情略多,最近更新的不勤了,但是学习的脚步不能停,一旦停下来,有些路就白走了,今天就盘点一下R语言和Python中常用于处理重复值、缺失值的函数。 在R...

34640
来自专栏Bingo的深度学习杂货店

Q152 Maximum Product Subarray

Find the contiguous subarray within an array (containing at least one number) wh...

43370
来自专栏简书专栏

基于Python装饰器的向量化计算速度对比

timer是一个装饰器,功能是给被装饰的函数计时。如果要进一步了解装饰器的使用,点击此链接Python闭包函数和装饰器 sumOfLoop函数是常规的使用fo...

11620

扫码关注云+社区

领取腾讯云代金券