关于稀疏矩阵的压缩存储与基本运算

对于基本类型数组,比如int数组,如果new了之后没有显式的初始化,数组中的元素值将自动初始化为0,如果是float数组值为0.0,
而对于对象数组将被初始化为null。
稀疏矩阵可以说是存在较多的0(int数组)或null值(对象数组),手动化初始的值较少的二维数组
(或多阶数组),稀疏矩阵的压缩存储是为了节省空间而对这类矩阵进行压缩存储。
所谓的压缩存储是:为多个相同的值分配一个存储空间,为null或0不分配空间。
前者只能是对特殊矩阵(比如对称矩阵或特殊矩阵)的压缩,这里只讨论的是后者。
直接上代码,注释完善
Java代码   收藏代码
  1. import java.util.Arrays;  
  2.   
  3. /** 
  4.  * 关于稀疏矩阵的压缩存储与基本运算 
  5.  * 压缩存储只存储矩阵的非空元素 
  6.  * 数组索引都是从0开始 
  7.  */  
  8. public class MatrixDemo<E> {  
  9.       
  10.     public static void main(String[] args) {  
  11.         MatrixDemo<Integer> md = new MatrixDemo<Integer>();  
  12.         Integer[][] M = new Integer[6][7];  
  13.         M[0][1] = 12; M[0][2] = 9;  
  14.         M[2][0] = -3; M[2][5] = 14;  
  15.         M[3][2] = 24; M[4][1] = 18;  
  16.         M[5][0] = 15; M[5][3] = -7;  
  17.   
  18.         //md.compreMatrix(M);  
  19.           
  20.         Integer[][] m = new Integer[3][4];  
  21.         m[0][0]=3;m[0][3]=5;  
  22.         m[1][1]=-1;m[2][0]=2;  
  23.         Integer[][] n = new Integer[4][2];  
  24.         n[0][0]=5;n[0][1]=2;  n[1][0]=1;  
  25.         n[2][0]=-2; n[2][1]=4;  
  26.         md.multiMatrix(m, n);  
  27.         System.out.println();  
  28.         md.multiMatrix(md.compreMatrix(m), md.compreMatrix(n));  
  29.     }  
  30.       
  31.       
  32.     /** 
  33.      * 把稀疏矩阵进行压缩 
  34.      */  
  35.     public Matrix compreMatrix(E[][] e){  
  36.         Matrix matrix = new Matrix();  
  37.         int mu = e.length;  
  38.         int nu = e[0].length;  
  39.         for(int i=0;i<mu;i++){  
  40.             for(int j=0;j<nu;j++){  
  41.                 if(e[i][j] != null){    //压缩非空元素  
  42.                     Triple<E> triple = new Triple<E>(i,j,e[i][j]);  
  43.                     matrix.add(triple);  
  44.                 }  
  45.             }  
  46.         }  
  47.         matrix.mu = mu;  
  48.         matrix.nu = nu;  
  49.           
  50.         //下面是查看元素  
  51.         for(int i=0;i<matrix.tu;i++){  
  52.             Triple<E> t = matrix.data[i];  
  53.             System.out.print(t.i + " " + t.j + " " + t.e);  
  54.             System.out.println();  
  55.         }  
  56.         System.out.println("----------");  
  57. //      transMatrix(matrix);  
  58. //      transMatrix2(matrix);  
  59.         return matrix;  
  60.     }  
  61.       
  62.     /** 
  63.      * 压缩矩阵的转置,方法一 
  64.      * 原理:1.将矩阵的行列对应的值相互交换 
  65.      *       2.将矩阵的行列下标交换 
  66.      *       3.重新排列新矩阵的顺序(按行排,即行中非空元素出现的次序) 
  67.      */  
  68.     public Matrix transMatrix(Matrix m){  
  69.         Matrix t = new Matrix();    //转置后的矩阵  
  70.         t.mu = m.nu;  
  71.         t.nu = m.mu;  
  72.   
  73.         if(m.tu == 0return null;  
  74.         for(int col=0; col<m.nu;col++){  //根据m的列的顺序排列转换矩阵的顺序  
  75.             for(int p=0;p<m.tu;p++){  
  76.                 if(m.data[p].j == col){  
  77.                     Triple<E> triple = new Triple<E>(m.data[p].j, m.data[p].i, (E)m.data[p].e);  
  78.                     t.add(triple);  
  79.                 }  
  80.             }  
  81.         }  
  82.         System.out.println("矩阵置换方法一");  
  83.         for(int i=0;i<t.tu;i++){  
  84.             Triple<E> tr = t.data[i];  
  85.             System.out.print(tr.i + " " + tr.j + " " + tr.e);  
  86.             System.out.println();  
  87.         }  
  88.         return t;  
  89.     }  
  90.       
  91.     /** 
  92.      * 压缩矩阵的转置,方法二 
  93.      * 原理:欲求得转置后的矩阵t的顺序,可以先求得m的每一列的第一个非空元素在 
  94.      * t中的索引cpot[col],并确定m每一列中的非空元素的个数num[col] 
  95.      * 公式很容易得到:1.cpot[0] = 0; 
  96.      *                2.cpot[col] = cpot[col - 1]+ num[col-1] (1<col<m.nu) 
  97.      */  
  98.     public Matrix transMatrix2(Matrix m){  
  99.         Matrix t = new Matrix();    //转置后的矩阵  
  100.         t.mu = m.nu;  
  101.         t.nu = m.mu;  
  102.           
  103.         //num和cpot数组的初始化  
  104.         int[] num = new int[m.nu];  
  105.         for(int ti=0;ti<m.tu;ti++){  //num初始化  
  106.             num[m.data[ti].j]++;  
  107.         }  
  108.         int[] cpot = new int[m.nu];  
  109.         cpot[0] = 0;  
  110.         //求第col列中第一个非空元素在t中的位置  
  111.         for(int col=1;col<m.nu;col++){   //cpot初始化  
  112.             cpot[col] = cpot[col-1] + num[col - 1];  
  113.         }  
  114.         //进行转换  
  115.         for(int p=0;p<m.tu;p++){  
  116.             int col = m.data[p].j;  
  117.             int q = cpot[col];  
  118.             Triple<E> triple = new Triple<E>(m.data[p].j, m.data[p].i, (E)m.data[p].e);  
  119.             t.add(q, triple);  
  120.             cpot[col]++;    //这个位置的下一个位置存储此列的下一个元素  
  121.         }  
  122.         //查看  
  123.         System.out.println("矩阵置换方法二");  
  124.         for(int i=0;i<t.tu;i++){  
  125.             Triple<E> tr = t.data[i];  
  126.             System.out.print(tr.i + " " + tr.j + " " + tr.e);  
  127.             System.out.println();  
  128.         }  
  129.         return t;  
  130.     }  
  131.       
  132.     /** 
  133.      * 两稀疏矩阵相乘。 
  134.      * 前提:1.矩阵元素能够相乘  
  135.      *       2.一个矩阵的列等于另一个矩阵的行 
  136.      * 原理:假设两矩阵M与N相乘,前提M的列M.col要等于N的行N.row(反之亦可) 
  137.      * 得到结果矩阵Q, Q.row=M.row, Q.col = N.col  
  138.      * 而且Q[i][j] += M[i][k] * N[k][j]  0<i<M.row,0<j<N.col,0<k<M.col或N.row   
  139.      */  
  140.     public Integer[][] multiMatrix(Integer[][] m,Integer[][] n){  
  141.         Integer[][] q = new Integer[m.length][n[0].length];  
  142.         for(int i=0;i<m.length;i++){  
  143.             for(int j=0;j<n[0].length;j++){  
  144.                 int num = 0;  
  145.                 for(int k=0;k<n.length;k++){  
  146.                     num += (m[i][k]==null?0:m[i][k]) * (n[k][j]==null?0:n[k][j]);  
  147.                 }  
  148.                 q[i][j] = num;  
  149.             }  
  150.         }  
  151.         //打印结果  
  152.         for(int i=0;i<q.length;i++){  
  153.             for(int j=0;j<q[0].length;j++){  
  154.                 System.out.print(q[i][j]+" ");  
  155.             }  
  156.             System.out.println();  
  157.         }  
  158.         return q;  
  159.     }  
  160.       
  161.     /** 
  162.      * 压缩矩阵的乘法运算 
  163.      * 稀疏矩阵进行乘法运算时即使含有0元素也相乘了, 
  164.      * 为避免这种情况,进行矩阵压缩后再相乘 
  165.      * 压缩矩阵相乘原理: 
  166.      * 1.先把稀疏矩阵进行压缩 
  167.      * 2.求出m与n的每一行的第一个非0元素在m与n中的位置 
  168.      * 3.遍历m每行的非0元素, 
  169.      */  
  170.     public Matrix multiMatrix(Matrix m,Matrix n){  
  171.         Matrix q = new Matrix();  
  172.         q.mu = m.mu;  
  173.         q.nu = n.nu;  
  174.         //初始化各行第一个非0元素的位置表  
  175.         int[] mNum = new int[m.mu];  
  176.         for(int len=0;len<m.tu;len++){   //每行有多少个非0元素  
  177.             mNum[m.data[len].i]++;  
  178.         }  
  179.         m.rpos = new int[m.mu];  
  180.         m.rpos[0] = 0;  
  181.         for(int mRow=1;mRow<m.mu;mRow++){    //每行第一个非0元素在m中的位置  
  182.             m.rpos[mRow] = m.rpos[mRow-1] + mNum[mRow-1];  
  183.         }  
  184.         int[] nNum = new int[n.mu];  
  185.         for(int len=0;len<n.tu;len++){   //每行有多少个非0元素  
  186.             nNum[n.data[len].i]++;  
  187.         }  
  188.         n.rpos = new int[n.mu];  
  189.         n.rpos[0] = 0;  
  190.         for(int nRow=1;nRow<n.mu;nRow++){    //每行第一个非0元素在n中的位置  
  191.             n.rpos[nRow] = n.rpos[nRow-1] + nNum[nRow-1];  
  192.         }  
  193.   
  194.         //初始化完毕,开始计算  
  195.         if(m.tu * n.tu !=0){  
  196.             for(int arow=0;arow<m.mu;arow++){  //一行一行处理  
  197.                 int mlast=0;  
  198.                 if(arow < m.mu-1)  
  199.                     mlast = m.rpos[arow+1];  
  200.                 else  
  201.                     mlast = m.tu;  
  202.                 for(int p=m.rpos[arow];p<mlast;p++){ //从这一行第一个非0索引到最后一个非0索引  
  203.                     int brow = m.data[p].j; //由于m.j=n.i,由此可以求出与此m元素相乘的n元素  
  204.                     int nlast=0;  
  205.                     if(brow < n.mu-1)  
  206.                         nlast = n.rpos[brow+1];  
  207.                     else  
  208.                         nlast = n.tu;  
  209.                     for(int w=n.rpos[brow];w<nlast;w++){  
  210.                         int ccol = n.data[w].j; //同一行的非0元素的列索引必然不相同  
  211.                         int sum = (Integer)m.data[p].e * (Integer)n.data[w].e;    
  212.                         if(sum!=0){     //除去0元素  
  213.                             Triple<Integer> triple = new Triple<Integer>(arow, ccol , sum);  
  214.                             q.add(triple);  
  215.                         }  
  216.                     }  
  217.                 }  
  218.             }  
  219.         }  
  220.         //打印结果  
  221.         for(int i=0;i<q.tu;i++){  
  222.             Triple<E> tr = q.data[i];  
  223.             System.out.print(tr.i + " " + tr.j + " " + tr.e);  
  224.             System.out.println();  
  225.         }  
  226.         return q;  
  227.     }  
  228.       
  229.     /** 
  230.      * 非空元素用三元组表示 
  231.      */  
  232.     class Triple<E>{  
  233.         int i;  //元素的行下标  
  234.         int j;  //元素的列下标  
  235.         E e;    //元素值  
  236.         Triple(int i,int j,E e) {  
  237.             this.i = i;  
  238.             this.j = j;  
  239.             this.e = e;  
  240.         }  
  241.     }  
  242.     /** 
  243.      * 压缩矩阵 
  244.      */  
  245.     class Matrix{  
  246.         Triple[] data;   //存储三元组的数组  
  247.         int mu;     //矩阵的行数  
  248.         int nu;     //矩阵的列数  
  249.         int tu;     //非空个数  
  250.         int[] rpos;  //各行第一个非0元素的位置表  
  251.         public Matrix(){  
  252.             this(10);  
  253.         }  
  254.           
  255.         public Matrix(int capacity) {  
  256.             data = new Triple[capacity];  
  257.         }  
  258.   
  259.         /** 
  260.          * 是否需要扩充容量 
  261.          */  
  262.         public void ensureCapacity(int minCapacity) {  
  263.             int oldCapacity = data.length;  
  264.             if (minCapacity > oldCapacity) { //指定最小容量比原来容量大才扩充  
  265.                 int newCapacity = (oldCapacity * 3) / 2 + 1;    //扩充原容量的1.5倍加1  
  266.                 if (newCapacity < minCapacity)   //扩充后还是小于要求的最小容量,则扩充容量为最小容量  
  267.                     newCapacity = minCapacity;  
  268.                 data = Arrays.copyOf(data, newCapacity);  
  269.             }  
  270.         }  
  271.         //添加元素到压缩矩阵  
  272.         public boolean add(Triple triple){  
  273.             ensureCapacity(tu + 1);   
  274.             data[tu++] = triple;    //size++  
  275.             return true;  
  276.         }  
  277.           
  278.         //在指定位置添加元素(此添加非彼添加)  
  279.         public boolean add(int index,Triple triple){  
  280.             if (index >= tu || index < 0//检查是否越界  
  281.                 throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ tu);  
  282.             ensureCapacity(tu + 1);   
  283.             data[index] = triple;     
  284.             tu++;  
  285.             return true;  
  286.         }  
  287.     }  
  288.       
  289.       


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值