`
zhouYunan2010
  • 浏览: 207670 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类

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

阅读更多
对于基本类型数组,比如int数组,如果new了之后没有显式的初始化,数组中的元素值将自动初始化为0,如果是float数组值为0.0,
而对于对象数组将被初始化为null。
稀疏矩阵可以说是存在较多的0(int数组)或null值(对象数组),手动化初始的值较少的二维数组
(或多阶数组),稀疏矩阵的压缩存储是为了节省空间而对这类矩阵进行压缩存储。
所谓的压缩存储是:为多个相同的值分配一个存储空间,为null或0不分配空间。
前者只能是对特殊矩阵(比如对称矩阵或特殊矩阵)的压缩,这里只讨论的是后者。
直接上代码,注释完善
import java.util.Arrays;

/**
 * 关于稀疏矩阵的压缩存储与基本运算
 * 压缩存储只存储矩阵的非空元素
 * 数组索引都是从0开始
 */
public class MatrixDemo<E> {
	
	public static void main(String[] args) {
		MatrixDemo<Integer> md = new MatrixDemo<Integer>();
		Integer[][] M = new Integer[6][7];
		M[0][1] = 12; M[0][2] = 9;
		M[2][0] = -3; M[2][5] = 14;
		M[3][2] = 24; M[4][1] = 18;
		M[5][0] = 15; M[5][3] = -7;

	    //md.compreMatrix(M);
	    
	    Integer[][] m = new Integer[3][4];
	    m[0][0]=3;m[0][3]=5;
	    m[1][1]=-1;m[2][0]=2;
	    Integer[][] n = new Integer[4][2];
	    n[0][0]=5;n[0][1]=2;  n[1][0]=1;
	    n[2][0]=-2; n[2][1]=4;
	    md.multiMatrix(m, n);
	    System.out.println();
	    md.multiMatrix(md.compreMatrix(m), md.compreMatrix(n));
	}
	
	
	/**
	 * 把稀疏矩阵进行压缩
	 */
	public Matrix compreMatrix(E[][] e){
		Matrix matrix = new Matrix();
		int mu = e.length;
		int nu = e[0].length;
		for(int i=0;i<mu;i++){
			for(int j=0;j<nu;j++){
				if(e[i][j] != null){	//压缩非空元素
					Triple<E> triple = new Triple<E>(i,j,e[i][j]);
					matrix.add(triple);
				}
			}
		}
		matrix.mu = mu;
		matrix.nu = nu;
		
		//下面是查看元素
		for(int i=0;i<matrix.tu;i++){
			Triple<E> t = matrix.data[i];
			System.out.print(t.i + " " + t.j + " " + t.e);
			System.out.println();
		}
		System.out.println("----------");
//		transMatrix(matrix);
//		transMatrix2(matrix);
		return matrix;
	}
	
	/**
	 * 压缩矩阵的转置,方法一
	 * 原理:1.将矩阵的行列对应的值相互交换
	 * 		 2.将矩阵的行列下标交换
	 * 		 3.重新排列新矩阵的顺序(按行排,即行中非空元素出现的次序)
	 */
	public Matrix transMatrix(Matrix m){
		Matrix t = new Matrix();	//转置后的矩阵
		t.mu = m.nu;
		t.nu = m.mu;

		if(m.tu == 0) return null;
		for(int col=0; col<m.nu;col++){	//根据m的列的顺序排列转换矩阵的顺序
			for(int p=0;p<m.tu;p++){
				if(m.data[p].j == col){
					Triple<E> triple = new Triple<E>(m.data[p].j, m.data[p].i, (E)m.data[p].e);
					t.add(triple);
				}
			}
		}
		System.out.println("矩阵置换方法一");
		for(int i=0;i<t.tu;i++){
			Triple<E> tr = t.data[i];
			System.out.print(tr.i + " " + tr.j + " " + tr.e);
			System.out.println();
		}
		return t;
	}
	
	/**
	 * 压缩矩阵的转置,方法二
	 * 原理:欲求得转置后的矩阵t的顺序,可以先求得m的每一列的第一个非空元素在
	 * t中的索引cpot[col],并确定m每一列中的非空元素的个数num[col]
	 * 公式很容易得到:1.cpot[0] = 0;
	 * 		 		  2.cpot[col] = cpot[col - 1]+ num[col-1] (1<col<m.nu)
	 */
	public Matrix transMatrix2(Matrix m){
		Matrix t = new Matrix();	//转置后的矩阵
		t.mu = m.nu;
		t.nu = m.mu;
		
		//num和cpot数组的初始化
		int[] num = new int[m.nu];
		for(int ti=0;ti<m.tu;ti++){	//num初始化
			num[m.data[ti].j]++;
		}
		int[] cpot = new int[m.nu];
		cpot[0] = 0;
		//求第col列中第一个非空元素在t中的位置
		for(int col=1;col<m.nu;col++){	//cpot初始化
			cpot[col] = cpot[col-1] + num[col - 1];
		}
		//进行转换
		for(int p=0;p<m.tu;p++){
			int col = m.data[p].j;
			int q = cpot[col];
			Triple<E> triple = new Triple<E>(m.data[p].j, m.data[p].i, (E)m.data[p].e);
			t.add(q, triple);
			cpot[col]++;	//这个位置的下一个位置存储此列的下一个元素
		}
		//查看
		System.out.println("矩阵置换方法二");
		for(int i=0;i<t.tu;i++){
			Triple<E> tr = t.data[i];
			System.out.print(tr.i + " " + tr.j + " " + tr.e);
			System.out.println();
		}
		return t;
	}
	
	/**
	 * 两稀疏矩阵相乘。
	 * 前提:1.矩阵元素能够相乘 
	 * 		 2.一个矩阵的列等于另一个矩阵的行
	 * 原理:假设两矩阵M与N相乘,前提M的列M.col要等于N的行N.row(反之亦可)
	 * 得到结果矩阵Q, Q.row=M.row, Q.col = N.col 
	 * 而且Q[i][j] += M[i][k] * N[k][j]  0<i<M.row,0<j<N.col,0<k<M.col或N.row  
	 */
	public Integer[][] multiMatrix(Integer[][] m,Integer[][] n){
		Integer[][] q = new Integer[m.length][n[0].length];
		for(int i=0;i<m.length;i++){
			for(int j=0;j<n[0].length;j++){
				int num = 0;
				for(int k=0;k<n.length;k++){
					num += (m[i][k]==null?0:m[i][k]) * (n[k][j]==null?0:n[k][j]);
 				}
				q[i][j] = num;
			}
		}
		//打印结果
		for(int i=0;i<q.length;i++){
			for(int j=0;j<q[0].length;j++){
				System.out.print(q[i][j]+" ");
			}
			System.out.println();
		}
		return q;
	}
	
	/**
	 * 压缩矩阵的乘法运算
	 * 稀疏矩阵进行乘法运算时即使含有0元素也相乘了,
	 * 为避免这种情况,进行矩阵压缩后再相乘
	 * 压缩矩阵相乘原理:
	 * 1.先把稀疏矩阵进行压缩
	 * 2.求出m与n的每一行的第一个非0元素在m与n中的位置
	 * 3.遍历m每行的非0元素,
	 */
	public Matrix multiMatrix(Matrix m,Matrix n){
		Matrix q = new Matrix();
		q.mu = m.mu;
		q.nu = n.nu;
		//初始化各行第一个非0元素的位置表
		int[] mNum = new int[m.mu];
		for(int len=0;len<m.tu;len++){	//每行有多少个非0元素
			mNum[m.data[len].i]++;
		}
		m.rpos = new int[m.mu];
		m.rpos[0] = 0;
		for(int mRow=1;mRow<m.mu;mRow++){	//每行第一个非0元素在m中的位置
			m.rpos[mRow] = m.rpos[mRow-1] + mNum[mRow-1];
		}
		int[] nNum = new int[n.mu];
		for(int len=0;len<n.tu;len++){	//每行有多少个非0元素
			nNum[n.data[len].i]++;
		}
		n.rpos = new int[n.mu];
		n.rpos[0] = 0;
		for(int nRow=1;nRow<n.mu;nRow++){	//每行第一个非0元素在n中的位置
			n.rpos[nRow] = n.rpos[nRow-1] + nNum[nRow-1];
		}

		//初始化完毕,开始计算
		if(m.tu * n.tu !=0){
			for(int arow=0;arow<m.mu;arow++){  //一行一行处理
				int mlast=0;
				if(arow < m.mu-1)
					mlast = m.rpos[arow+1];
				else
					mlast = m.tu;
				for(int p=m.rpos[arow];p<mlast;p++){	//从这一行第一个非0索引到最后一个非0索引
					int brow = m.data[p].j;	//由于m.j=n.i,由此可以求出与此m元素相乘的n元素
					int nlast=0;
					if(brow < n.mu-1)
						nlast = n.rpos[brow+1];
					else
						nlast = n.tu;
					for(int w=n.rpos[brow];w<nlast;w++){
						int ccol = n.data[w].j;	//同一行的非0元素的列索引必然不相同
						int sum = (Integer)m.data[p].e * (Integer)n.data[w].e;	
						if(sum!=0){		//除去0元素
							Triple<Integer> triple = new Triple<Integer>(arow, ccol , sum);
							q.add(triple);
						}
					}
				}
			}
		}
		//打印结果
		for(int i=0;i<q.tu;i++){
			Triple<E> tr = q.data[i];
			System.out.print(tr.i + " " + tr.j + " " + tr.e);
			System.out.println();
		}
		return q;
	}
	
	/**
	 * 非空元素用三元组表示
	 */
	class Triple<E>{
		int i;	//元素的行下标
		int j;	//元素的列下标
		E e;	//元素值
		Triple(int i,int j,E e) {
			this.i = i;
			this.j = j;
			this.e = e;
		}
	}
	/**
	 * 压缩矩阵
	 */
	class Matrix{
		Triple[] data;	 //存储三元组的数组
		int mu;		//矩阵的行数
		int nu;		//矩阵的列数
		int tu;		//非空个数
		int[] rpos;	 //各行第一个非0元素的位置表
		public Matrix(){
			this(10);
		}
		
		public Matrix(int capacity) {
			data = new Triple[capacity];
		}

		/**
		 * 是否需要扩充容量
		 */
		public void ensureCapacity(int minCapacity) {
			int oldCapacity = data.length;
			if (minCapacity > oldCapacity) {	//指定最小容量比原来容量大才扩充
				int newCapacity = (oldCapacity * 3) / 2 + 1;	//扩充原容量的1.5倍加1
				if (newCapacity < minCapacity)	//扩充后还是小于要求的最小容量,则扩充容量为最小容量
					newCapacity = minCapacity;
				data = Arrays.copyOf(data, newCapacity);
			}
		}
		//添加元素到压缩矩阵
		public boolean add(Triple triple){
			ensureCapacity(tu + 1); 
			data[tu++] = triple;	//size++
			return true;
		}
		
		//在指定位置添加元素(此添加非彼添加)
		public boolean add(int index,Triple triple){
			if (index >= tu || index < 0)	//检查是否越界
				throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ tu);
			ensureCapacity(tu + 1); 
			data[index] = triple;	
			tu++;
			return true;
		}
	}
	
	
}


分享到:
评论

相关推荐

    稀疏 矩阵的压缩存储

    c 语言实现 稀疏矩阵 的创建 和 C语言 压缩存储 压缩矩阵转置

    顺序存储空间表示的稀疏矩阵的创建和矩阵运算

    这里我们将重点讨论连续存储空间表示的稀疏矩阵,这通常是指压缩存储中的行优先存储或列优先存储。 1. **稀疏矩阵的概念与特性** - 稀疏矩阵是指非零元素个数远小于矩阵总元素个数的矩阵。通常用非零元素的数量与...

    稀疏矩阵压缩存储及快速转置_C语言_

    本主题将深入探讨如何使用C语言实现稀疏矩阵的三元组压缩存储以及快速转置。 **稀疏矩阵的三元组压缩存储** 稀疏矩阵的三元组压缩存储方式是将非零元素按照行优先或列优先的顺序存储在一个二维数组中,每个元素...

    掌握稀疏矩阵的压缩存储存储方法。

    1、 掌握稀疏矩阵的压缩存储存储方法。 2、 能利用三元组顺序表表示并实现稀疏矩阵。 3、 会利用三元组顺序表实现矩阵的加法运算。 二、 实验要求 1、 进行加法运算的两个矩阵由用户输入。并且用三元组顺序表表示。...

    稀疏矩阵 的 加减乘除 运算

    "温国权 3107006955 稀疏矩阵.doc"可能是关于这个程序的文档,解释了实现细节和使用方法。"XSJZ.exe"是编译后的可执行文件,可以直接运行以测试程序的功能。 总之,稀疏矩阵的运算对于处理大规模稀疏数据至关重要,...

    稀疏矩阵运算器

    稀疏矩阵通常使用三种主要的存储结构:三元组(Triple Format)、压缩行存储(CRS, Compressed Row Storage)和压缩列存储(CCS, Compressed Column Storage)。在这个特定的“稀疏矩阵运算器”中,描述中提到的是三元组...

    稀疏矩阵的运算源代码实验报告,自己做的实验报告,传上来大家享用。

    因此,我们通常采用稀疏矩阵存储格式,如三元组存储((行索引,列索引,值))或压缩存储(链表或二叉树等)来优化存储和运算效率。 实验中,我们可能涉及以下几种基本的稀疏矩阵运算: 1. **构造**:从一个普通的...

    稀疏矩阵的存储与转置转置

    ### 稀疏矩阵的存储与转置 #### 一、引言 在计算机科学领域,稀疏矩阵是指大部分元素为零的矩阵。对于这类矩阵,如果采用传统的二维数组进行存储,不仅会占用大量内存空间,而且对于某些操作(如矩阵乘法)效率极...

    数据结构课程设计-稀疏矩阵运算器

    在这个课程设计中,我们需要实现稀疏矩阵的四大基本运算:加法、减法、乘法和除法。每种运算都有其独特的算法挑战: 1. **加法**:两个稀疏矩阵相加,只需要对它们的非零元素进行对应位置的加法运算。如果某个位置...

    数据结构实验报告(稀疏矩阵)

    总的来说,这个实验报告提供了关于稀疏矩阵存储和运算的实践经验,强调了在处理零元素占主导的矩阵时,采用稀疏矩阵结构和算法的优势。通过实际操作,学生能够掌握稀疏矩阵的理论知识并应用到实践中,提升了对数据...

    稀疏矩阵的存储和乘法

    稀疏矩阵的存储通常采用两种主要方式:三元组(Triple)存储和压缩存储(如 compressed row storage, CRS 或 compressed column storage, CCS)。三元组存储方式简单直观,将每个非零元素用一个三元组 (行号, 列号, 值...

    稀疏矩阵运算器 C++

    通常,稀疏矩阵的存储格式有链表法、三元组法和压缩存储法(CSR, Compressed Sparse Row或CSC, Compressed Sparse Column)。 二、C++实现稀疏矩阵 1. 链表法:利用C++的结构体或类,定义节点包含元素值、行索引和...

    稀疏矩阵的压缩存储方法及主要运算的实现.doc

    总结来说,这个文件通过三元组和RLSMatrix结构展示了如何实现稀疏矩阵的压缩存储,并提供了加法、乘法和转置等基本运算的实现。这些知识对于理解如何高效处理大规模稀疏数据,特别是在图形学、数值计算和数据挖掘等...

    稀疏矩阵存储和转置及乘法 c++源代码 原创

    常见的稀疏矩阵存储方法有两种:三元组(Triple)存储和压缩存储(CRS:Compressed Row Storage或CCS:Compressed Column Storage)。在这个C++实现中,很可能采用了CRS方法,因为它更适合进行矩阵运算,如转置和乘法。...

    稀疏矩阵的转置

    CRS和CCS是两种常用的稀疏矩阵压缩存储方式: - CRS:适合行非零元素较少的情况,存储每个非零元素的列索引和值,以及每行非零元素的结束位置。 - CCS:适合列非零元素较少的情况,存储每个非零元素的行索引和值,...

    稀疏矩阵加减乘运算

    在VC6.0环境下实现稀疏矩阵运算,首先需要定义稀疏矩阵的数据结构,如三元组列表或压缩存储结构。然后,可以编写C++函数来实现加、减、乘操作。注意,由于VC6.0是一个较旧的IDE,可能不支持现代C++特性,所以代码...

    数据结构稀疏矩阵运算器

    6. **压缩存储**:在运算过程中,可能会出现新的零元素,为了保持稀疏矩阵的高效性,需要定期进行压缩存储,删除链表中的零元素节点。 7. **查找与修改**:根据用户提供的行号和列号,查找对应的非零元素并进行修改...

    稀疏矩阵运算器(vc)

    2. **压缩行存储(CRS)**:CRS格式是稀疏矩阵运算中最常用的格式之一。它将每一行的非零元素连续存储,并记录每行的起始位置。这使得按行访问变得快速,适用于行操作较多的情况。 3. **压缩列存储(CCS)**:CCS与CRS...

    数据结构 稀疏矩阵运算

    总之,理解和掌握稀疏矩阵的运算与存储对于高效处理大规模零元素矩阵至关重要,这不仅可以节省存储空间,还能显著提高计算效率。在实际应用中,根据矩阵的特性和运算需求选择合适的数据结构和算法是优化计算性能的...

Global site tag (gtag.js) - Google Analytics