稀疏矩阵压缩存储(C语言实现)

背景需求

在一个矩阵中,如果非0元素远远少于0元素,那么这个矩阵就是稀疏矩阵,在实际应用中,计算机会耗费大量的空间存储这些无意义的0元素,如果能够压缩一下,将会减少计算机的开销。本篇文章以五子棋的棋局保存为背景,用c语言实现原始稀疏矩阵转换为压缩矩阵并且存储为文件,棋局复盘则读取文件将压缩矩阵转换为原始稀疏矩阵。

图解

假如有如下棋局,如果要保存,可以用1来表示红棋子,2来表示黑棋子,0表示无棋子。

需求就是将上述棋局转换为如下矩阵

算法

棋局保存:1、统计有多少个有效元素count

                  2、定义长度为count+1,宽度为3的矩阵arr

                  3、逐一赋值,存入文件

棋局复盘:1、读取文件第一行,得到原始矩阵的行列数,定义原始矩阵

                  2、将文件中对应的非0值赋值给原始矩阵

棋局保存代码实现

#include <stdio.h>
#include <stdlib.h>
#define LEN 6
/**
求输出稀疏矩阵
*/
void showArr(int *arr, int row,int col){
	int num = row*col;
	int cnt = 0;
	for(int i = 0 ; i < num ; i++){
		
			printf("%4d",*(arr+i));
			cnt++;
			if(cnt%3==0) printf("\n");
	}
}
/**
求输出原始方阵
*/
void showoldArr(int arr[][LEN]){
	for(int i = 0 ; i < LEN ; i++){
		for(int j = 0 ; j < LEN ; j++){
			printf("%4d",arr[i][j]);
		}
		if(j == LEN) printf("\n");
	}
}
/**
求有效元素个数
*/
int arrNum(int arr[][LEN]){
	int count = 0;
	for(int i = 0 ; i < LEN ; i++){
		for(int j = 0 ; j < LEN ; j++){
			if(arr[i][j]!=0) count++;
		}
	}
	return count;
}
int main(){
	int i = 0,j=0,k = 0,m = 0;
	int oldArr[LEN][LEN] = {{0,1},{0,0,2},{1}};
	//1表示白棋子,2表示黑棋子,0表示无棋子
printf("原始矩阵:\n");
	showoldArr(oldArr);
	//得到有效数据的个数,确定稀疏矩阵的行数
	int num = arrNum(oldArr);
	int row = num+1;
	int col = 3;
	//创建稀疏矩阵,因为c语言中的二维数组长度不能含有变量,所以用指针的指针来定义
	int  *newArr;
	newArr=(int *)malloc(sizeof(int)*(num+1)*3);

//先给稀疏矩阵的第一行赋值
	*newArr = LEN;
	*(newArr+1) = LEN;
	*(newArr+2) = num;
//再给剩下的行赋值	
	for(i = 3 ; i < row*col ; i+=3){
				for(; k < LEN ; ){
					for(m = 0 ; m < LEN ; m++){
						if(oldArr[k][m]!=0){
							*(newArr+i) = k;
							*(newArr+i+1) = m;
							*(newArr+i+2) = oldArr[k][m];
						}
					}
					k+=1;
					break;
				}
	}
	printf("稀疏矩阵:\n");
	showArr(newArr,row,col);
//将矩阵写入文件
	FILE *p=fopen("arr.txt","w");
	for(i = 0 ; i < row*col ;){

		fprintf(p,"%d",*(newArr+i));
		i++;
		if(i%3==0&&i!=row*col) fprintf(p,"%s","\n");
	}

	fclose(p);

}

棋局保存运行结果

棋局复盘代码实现

#include <stdio.h>
#include <stdlib.h>
/**
	输出原始数组
*/
void showArr(int *arr, int row,int col){
	int num = row*col;
	int cnt = 0;
	for(int i = 0 ; i < num ; i++){
		
			printf("%4d",*(arr+i));
			cnt++;
			if(cnt%row==0) printf("\n");
	}
}
int main(){
	char line[256];
	
	FILE *f = fopen("arr.txt", "rb");
	//先读第一行
	fgets(line, 256, f);
	int ele =	atoi(line);
	char rlen =ele/100;			//得到矩阵长度
	char clen =ele/10%10;		//得到矩阵宽度
	int *arr;	//定义一个空间来放原始矩阵
	arr = (int *)malloc(sizeof(int)*rlen*clen);//根据矩阵长度宽度开辟空间
	for(int j = 0;j<rlen*clen;j++){*(arr+j) =0;} //先将所有的值赋值为0

	while (!feof(f) && !ferror(f)) {	//开始按行读取数据
		fgets(line,sizeof(line),f);
		
		for(int i = 0;i<rlen*clen;i++){
			
			int ele =atoi(line);	
			int row = ele/100;	//得到行
			int col = ele/10%10;	//得到列
			int val = ele%10;//得到值

			if((row*rlen+col)==i)	//如果此时的行列正好是目标行列,赋值即可
				*(arr+i) = val;
		}
	}
	showArr(arr,rlen,clen);
    fclose(f);
    return 0;
}


棋局复盘运行结果

总结

c语言中,数组的长度定义不可以为变量,必须是常量,因此这里便用指针开辟空间来代替二维数组,实际上二维数组的物理内存和一位数组一样,都是线性存储,因此实质上是一样的。指针的取值怎么取也是容易出错的地方,如果写错表达式,会出现程序停止。

  • 6
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值