java 稀疏矩阵

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/itnerd/article/details/83038384

稀疏矩阵 一般用 (x, y, value) 三元组来存储矩阵非零元素,当矩阵只有少量非零元素时,可以大大减少存储空间。

本文实现的稀疏矩阵只实现了

  • 一般矩阵 和 稀疏矩阵 之间的转换
  • 读取稀疏元素
  • 存储稀疏元素
package matrix;

import java.util.HashMap;
import java.util.Map;

public class SparseMatrix{

	Map<String, Double> pairs= new HashMap<>();
	int rowNum,colNum;
	boolean sizeFixed;

	// 如果没有初始化矩阵维数,稀疏矩阵大小可变
	public SparseMatrix(){
		sizeFixed = false;
	}
	public SparseMatrix(int r, int c){
		sizeFixed = true;
		rowNum = r;
		colNum = c;
	}
	public int getRowNum() {
		return rowNum;
	}
	public int getColNum() {
		return colNum;
	}
	
	// 添加矩阵元素
	public void put(int x, int y, double v) throws IndexException{
		checkIndex(x,y);
		if(v != 0)
			pairs.put(SparseIndex(x,y),v);
	}
	
	// 获取矩阵元素
	public Double get(int x, int y) throws IndexException{
		checkIndex(x,y);
		Double v = pairs.get(SparseIndex(x,y));
		if(v == null) {
			v = Double.valueOf(0);
		}
		return v;
	}
	
	// 转换为 一般矩阵
	public double[][] toDensity(){
		double[][] mat = new double[rowNum][colNum];
		for(int i=0; i<rowNum; ++i) {
			for(int j=0; j<colNum; ++j) {
				try {
					mat[i][j] = get(i,j);
				} catch (IndexException e) {
				}
			}
		}
		return mat;
	}
	
	// 从一般矩阵 转换为 稀疏矩阵
	static public SparseMatrix fromDensity(double [][] mat){
		SparseMatrix sm = new SparseMatrix(mat.length,mat[0].length);
		for(int i=0; i<mat.length; ++i) {
			for(int j=0; j<mat[0].length; ++j) {
				try {
					if(mat[i][j] != 0) {
						sm.put(i,j,mat[i][j]);
					}
				} catch (IndexException e) {
				}
			}
		}
		return sm;
	}
	
	// 把矩阵索引转换成字符串,用于哈希索引 
	static public String SparseIndex(int x, int y){
		return String.valueOf(x)+","+String.valueOf(y);
	}
	
	// 检查是否越界,下标越界则抛出异常
	private void checkIndex(int x, int y) throws IndexException{
		if(sizeFixed) {
			if(x >= rowNum || y >= colNum) {
				throw new IndexException(
						"Index out of bound: ("+String.valueOf(x)+","+String.valueOf(y)+"), "+
						"(rowNum,colNum)=("+String.valueOf(rowNum)+","+String.valueOf(colNum)+")."
						);
			}
		}else {
			rowNum = rowNum>x+1?rowNum:x+1;
			colNum = colNum>y+1?colNum:y+1;
		}
	}
	
	// 自定义异常
	class IndexException extends Exception {
		public IndexException (String message){ 
			super (message); 
		}
		public IndexException (String message, Exception cause) {
			super(message,cause);
		}   
	}
	
	// 测试
	public static void main(String[] args) {
		SparseMatrix sm = new SparseMatrix();
		try {
			sm.put(0, 0, 1.0);
			sm.put(2, 1, 2.0);
			sm.put(1, 4, -9);
			
		} catch (SparseMatrix.IndexException e) {
			e.printStackTrace();
		}
		double [][] mat = SparseMatrix.fromDensity(sm.toDensity()).toDensity();
		for(int i=0; i<sm.getRowNum(); ++i) {
			for(int j=0; j<sm.getColNum(); ++j) {
				System.out.print(mat[i][j]);
				System.out.print(" ");
			}
			System.out.println();
		}
	}
}


测试结果:

1.0 0.0 0.0 0.0 0.0 
0.0 0.0 0.0 0.0 -9.0 
0.0 2.0 0.0 0.0 0.0 

为了方便读取某一行更方便,稍作修改:

package matrix;

import java.util.HashMap;
import java.util.Map;

public class SparseMatrix{

	protected Map<Integer,Map<Integer, Double>> rows = new HashMap<>();
	int rowNum,colNum;
	boolean sizeFixed;
	Double DEFAULT_VALUE = Double.valueOf(0); //矩阵元素默认值, 在图的邻接矩阵中可设为无穷大

	// 如果没有初始化矩阵维数,稀疏矩阵大小可变
	public SparseMatrix(){
		sizeFixed = false;
	}
	public SparseMatrix(int r, int c){
		sizeFixed = true;
		rowNum = r;
		colNum = c;
	}
	
	public int getRowNum() {
		return rowNum;
	}
	public int getColNum() {
		return colNum;
	}
	
	public void setDefaultValue(double def) {
		DEFAULT_VALUE = Double.valueOf(def);
	}
	
	// 添加矩阵元素
	public void put(int x, int y, double v) throws IndexException{
		checkIndex(x,y);
		if(v != DEFAULT_VALUE) {
			Map<Integer,Double> row = rows.get(x);
			if(null == row) {
				row = new HashMap<Integer,Double>();
			}
			row.put(y, v);
			rows.put(x, row);
		}
	}
	
	// 获取矩阵元素
	public Double get(int x, int y) throws IndexException{
		checkIndex(x,y);
		Map<Integer,Double> row = rows.get(x);
		if(row == null) {
			return DEFAULT_VALUE;
		}
		Double v = row.get(y);
		if(v == null) {
			v = DEFAULT_VALUE;
		}
		return v;
	}
	
	// 转换为 一般矩阵
	public double[][] toDensity(){
		double[][] mat = new double[rowNum][colNum];
		for(int i=0; i<rowNum; ++i) {
			for(int j=0; j<colNum; ++j) {
				try {
					mat[i][j] = get(i,j);
				} catch (IndexException e) {
				}
			}
		}
		return mat;
	}
	
	// 从一般矩阵 转换为 稀疏矩阵
	static public SparseMatrix fromDensity(double [][] mat){
		SparseMatrix sm = new SparseMatrix(mat.length,mat[0].length);
		for(int i=0; i<mat.length; ++i) {
			for(int j=0; j<mat[0].length; ++j) {
				try {
					if(mat[i][j] != 0) {
						sm.put(i,j,mat[i][j]);
					}
				} catch (IndexException e) {
				}
			}
		}
		return sm;
	}
	
	
	// 检查是否越界,下标越界则抛出异常
	private void checkIndex(int x, int y) throws IndexException{
		if(sizeFixed) {
			if(x >= rowNum || y >= colNum) {
				throw new IndexException(
					"Index out of bound: ("+String.valueOf(x)+","+String.valueOf(y)+"), "+
					"(rowBound,colBound)=("+String.valueOf(rowNum)+","+String.valueOf(colNum)+")."
					);
			}
		}else {
			rowNum = rowNum>x+1?rowNum:x+1;
			colNum = colNum>y+1?colNum:y+1;
		}
	}
	
	// 自定义异常
	public class IndexException extends Exception {
		public IndexException (String message){ 
			super (message); 
		}
		public IndexException (String message, Exception cause) {
			super(message,cause);
		}   
	}
	
	// 测试
	public static void main(String[] args) {
		SparseMatrix sm = new SparseMatrix();
		try {
			sm.put(0, 0, 1.0);
			sm.put(2, 1, 2.0);
			sm.put(1, 4, -9);
			
		} catch (SparseMatrix.IndexException e) {
			e.printStackTrace();
		}
		double [][] mat = SparseMatrix.fromDensity(sm.toDensity()).toDensity();
		for(int i=0; i<sm.getRowNum(); ++i) {
			for(int j=0; j<sm.getColNum(); ++j) {
				System.out.print(mat[i][j]);
				System.out.print(" ");
			}
			System.out.println();
		}
	}
}

最后,我们来把稀疏矩阵的元素类型变成 Object,就可以适用各种元素类型的矩阵了。在 java 中使用 Object 要比用泛型方便的多,省时又省力。

这么做的初衷是在图优化的最大流问题中,需要存储每条边的上下界,这样一来,每条边对应了两个数,就需要用个对象来表示了。

来,上代码!

package matrix;

import java.util.HashMap;
import java.util.Map;

public class SparseMatrix {

	protected Map<Integer, Map<Integer, Object>> rows = new HashMap<>();
	int rowNum, colNum;
	boolean sizeFixed;
	Object DEFAULT_VALUE = null; // 矩阵元素默认值, 在图的邻接矩阵中可设为无穷大

	// 如果没有初始化矩阵维数,稀疏矩阵大小可变
	public SparseMatrix() {
		sizeFixed = false;
	}

	public SparseMatrix(int r, int c) {
		sizeFixed = true;
		rowNum = r;
		colNum = c;
	}

	// getter & setter
	public int getRowNum() {
		return rowNum;
	}

	public int getColNum() {
		return colNum;
	}

	public void setDefaultValue(Object def) {
		DEFAULT_VALUE = def;
	}

	// 添加矩阵元素
	public void put(int x, int y, Object v) throws IndexException, TypeException {
		checkIndexAndType(x, y, v);
		if (v != DEFAULT_VALUE) {
			Map<Integer, Object> row = rows.get(x);
			if (null == row) {
				row = new HashMap<Integer, Object>();
			}
			row.put(y, v);
			rows.put(x, row);
		}
	}

	// 获取矩阵元素
	public Object get(int x, int y) throws IndexException {
		checkIndex(x, y);
		Map<Integer, Object> row = rows.get(x);
		if (row == null) {
			return DEFAULT_VALUE;
		}
		Object v = row.get(y);
		if (v == null) {
			v = DEFAULT_VALUE;
		}
		return v;
	}

	// 转换为 一般矩阵
	public Object[][] toDensity() {
		Object[][] mat = new Object[rowNum][colNum];
		for (int i = 0; i < rowNum; ++i) {
			for (int j = 0; j < colNum; ++j) {
				try {
					mat[i][j] = get(i, j);
				} catch (IndexException e) {
					e.printStackTrace();
				}
			}
		}
		return mat;
	}

	// 从一般矩阵 转换为 稀疏矩阵
	public SparseMatrix fromDensity(Object[][] mat) {
		SparseMatrix sm = new SparseMatrix(mat.length, mat[0].length);
		sm.setDefaultValue(DEFAULT_VALUE);
		try {
			for (int i = 0; i < mat.length; ++i) {
				for (int j = 0; j < mat[0].length; ++j) {
					if (mat[i][j] != DEFAULT_VALUE) {
						sm.put(i, j, mat[i][j]);
					}
				}
			}
		} catch (IndexException | TypeException e) {
			e.printStackTrace();
		}
		return sm;
	}

	// 检查是否越界,下标越界则抛出异常
	private void checkIndex(int x, int y) throws IndexException {
		if (sizeFixed) {
			if (x >= rowNum || y >= colNum) {
				throw new IndexException("Index out of bound: (" + String.valueOf(x) + "," + String.valueOf(y) + "), "
						+ "(rowBound,colBound)=(" + String.valueOf(rowNum) + "," + String.valueOf(colNum) + ").");
			}
		} else {
			rowNum = rowNum > x + 1 ? rowNum : x + 1;
			colNum = colNum > y + 1 ? colNum : y + 1;
		}
	}

	// 检查元素类型是否和默认值一致
	private void checkIndexAndType(int x, int y, Object o) throws TypeException, IndexException {
		checkIndex(x, y);
		if (o.getClass() != this.DEFAULT_VALUE.getClass()) {
			throw new TypeException("Invalid element type at location(" + x + "," + y + "). Expected: "
					+ this.DEFAULT_VALUE.getClass() + ", Got: " + o.getClass());
		}
	}

	// 自定义异常
	public class IndexException extends Exception {
		public IndexException(String message) {
			super(message);
		}

		public IndexException(String message, Exception cause) {
			super(message, cause);
		}
	}

	// 自定义异常
	public class TypeException extends Exception {
		public TypeException(String message) {
			super(message);
		}

		public TypeException(String message, Exception cause) {
			super(message, cause);
		}
	}

	// 测试
	public static void main(String[] args) {
		SparseMatrix sm = new SparseMatrix();
		sm.setDefaultValue(Double.valueOf(0));
		try {
			sm.put(0, 0, 1.0);
			sm.put(2, 1, 2.0);
			sm.put(1, 4, -9.0);

		} catch (SparseMatrix.IndexException | TypeException e) {
			e.printStackTrace();
		}
		Object[][] mat = sm.fromDensity(sm.toDensity()).toDensity();
		for (int i = 0; i < sm.getRowNum(); ++i) {
			for (int j = 0; j < sm.getColNum(); ++j) {
				System.out.print(mat[i][j]);
				System.out.print(" ");
			}
			System.out.println();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/itnerd/article/details/83038384