稀疏矩阵压缩存储的C语言实现 (GCC编译)。

 /**
* @brief C语言 稀疏矩阵 压缩 实现
* @author wid
* @date 2013-11-04
*
* @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
*/ #include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h> #define TRUE 1
#define FALSE 0
#define NPOS -1 typedef int ElemType; typedef struct
{
int m; ///行下标
int n; ///列下标
ElemType elm; ///该下标所保存的元素
}TTuple; ///三元组结构 typedef struct
{
TTuple *tup; ///三元组顺序表
int row; ///矩阵行数
int col; ///矩阵列数
int unul; ///非 0 元素个数
}TMatrix; ///稀疏矩阵结构 ///稀疏矩阵方法声明
TMatrix *CreateEmptyTMatrix( int sizeM, int sizeN ); ///创建一个大小为 sizeM x sizeN 稀疏矩阵
TMatrix *CreateTMatirxFrom2DArray( void *pArr2D, int sizeM, int sizeN ); ///从二维数组中创建稀疏矩阵
void DestroyTMatrix( TMatrix *pMat ); ///销毁稀疏矩阵
int ElemLocate( const TMatrix *const pMat, int m, int n ); ///定位矩阵下标 m, n 在稀疏矩阵中的存储位置
void DisplayTMatrix( const TMatrix *const pMat ); ///输出稀疏矩阵
int GetTMatrixSize( const TMatrix *const pMat ); ///输出稀疏矩阵 pMat 所占用的空间大小(字节)
int AppendElem( TMatrix *const pMat, ElemType elm, int m, int n ); ///将元素 elm 添加到稀疏矩阵 m, n 位置
int DeleteElem( TMatrix *const pMat, int m, int n ); ///删除稀疏矩阵中 m, n 下标指向的元素
int TMatrixCopy( TMatrix *const pMatDest, TMatrix *const pMatSrc ); ///将稀疏矩阵 pMatSrc 复制到 pMatDest
int Value( const TMatrix *const pMat, int m, int n, ElemType *pElm ); ///从稀疏矩阵中取下标为 m, n 元素的值
void ForEach( const TMatrix *const pMat, void (*func)(ElemType *pElm) ); ///对矩阵中的每个元素依次执行 func 函数 ///稀疏矩阵方法实现 /**
* @brief 创建一个大小为 sizeM x sizeN 稀疏矩阵
*
* @return 返回创建的稀疏矩阵的指针
*/
TMatrix *CreateEmptyTMatrix( int sizeM, int sizeN )
{
///不接受大小为0的稀疏矩阵
assert( sizeM > && sizeN > ); TMatrix *pMat = (TMatrix *)malloc( sizeof(TMatrix) );
pMat->tup = NULL;
pMat->row = sizeM;
pMat->col = sizeN;
pMat->unul = ; return pMat;
} /**
* @brief 从二维数组中创建稀疏矩阵
*
* @param pArr2D 一个ElemType型二维数组
* @param sizeM 二维数组的行数
* @param sizeN 二维数组的列数
*
* @return 返回创建的稀疏矩阵的指针
*/
TMatrix *CreateTMatirxFrom2DArray( void *pArr2D, int sizeM, int sizeN )
{
///不接受大小为0的稀疏矩阵
assert( sizeM > && sizeN > ); TMatrix *pMat = (TMatrix *)malloc( sizeof(TMatrix) ); ///初始化稀疏矩阵行数、列数
pMat->row = sizeM;
pMat->col = sizeN; ///第一趟遍历, 统计非零元素个数
int m = , n = ;
for( m = ; m < sizeM; ++m )
for( n = ; n < sizeN; ++n )
if( ((ElemType *)pArr2D)[sizeM * m + n] != )
++pMat->unul; ///申请合适长度的三元组类型的线性表
pMat->tup = (TTuple *)calloc( pMat->unul, sizeof(TTuple) ); ///第二趟遍历, 存储二维矩阵中的非零元素
int nPos = ;
for( m = ; m < sizeM; ++m )
for( n = ; n < sizeN; ++n )
if( ((ElemType *)pArr2D)[sizeM * m + n] != )
{
pMat->tup[nPos].m = m;
pMat->tup[nPos].n = n;
pMat->tup[nPos].elm = ((ElemType *)pArr2D)[sizeM * m + n];
++nPos;
} return pMat;
} /**
* @brief 销毁稀疏矩阵
*
* @param pMat 指向待销毁的稀疏矩阵
*/
void DestroyTMatrix( TMatrix *pMat )
{
free( pMat->tup );
free( pMat ); pMat = NULL;
} /**
* @brief 定位元素下标 m, n 在稀疏矩阵中出现的位置
*
* @param pMat 指向待定位元素的稀疏矩阵
* @param m 元素行下标
* @param n 元素列下标
*
* @return 若存在, 返回该下标组在稀疏矩阵中出现的位置, 否则返回 NPOS
*
* @note 元素位置由 0 计起
*/
int ElemLocate( const TMatrix *const pMat, int m, int n )
{
int i = ;
for( i = ; i < pMat->unul; ++i )
{
if( pMat->tup[i].m == m && pMat->tup[i].n == n )
return i;
} return NPOS;
} /**‘
* @brief 输出稀疏矩阵
*
* @param pMat 指向待输出的稀疏矩阵
*
* @return void
*/
void DisplayTMatrix( const TMatrix *const pMat )
{
int m = , n = , pos = ;
for( m = ; m < pMat->row; ++m )
{
for( n = ; n < pMat->col; ++n )
{
pos = ElemLocate( pMat, m, n );
if( pos != NPOS )
printf( "%d ", pMat->tup[pos].elm );
else
printf( "%d ", );
}
putchar( '\n' );
}
} /**
* @brief 获取稀疏矩阵所占用的空间大小(字节)
*
* @param pMat 指向待获取占用空间的稀疏矩阵
*
* @return 返回该矩阵所占用的空间的大小
*/
int GetTMatrixSize( const TMatrix *const pMat )
{
return pMat->unul * sizeof(TTuple);
} /**
* @brief 将元素添加到稀疏矩阵的 m, n 位置
*
* @param pMat 指向待添加元素的稀疏矩阵
* @param elm 待添加的元素
* @param m 元素所在的行数
* @param n 元素所在的列数
*
* @return 返回添加后稀疏矩阵中非 0 元素的个数
*/
int AppendElem( TMatrix *const pMat, ElemType elm, int m, int n )
{
///断言下标合法
assert( m >= && m < pMat->row && n >= && n < pMat->col ); ///断言元素值合法(不接受元素值为0的元素)
assert( elm != ); ///测试下标是否存在
int i = , pos = ;
pos = ElemLocate( pMat, m, n );
if( pos != NPOS )
{ ///下标已存在, 覆盖原值
pMat->tup[pos].elm = elm;
return pMat->unul;
} ///新添加
pMat->tup = (TTuple *)realloc( pMat->tup, sizeof(TTuple) * (pMat->unul + ) );
pMat->tup[pMat->unul].m = m;
pMat->tup[pMat->unul].n = n;
pMat->tup[pMat->unul].elm = elm; return ++pMat->unul;
} /**
* @brief 删除稀疏矩阵中下标 m, n 指向的元素
*
* @param pMat 指向待删除元素的稀疏矩阵
* @param m 元素行下标
* @param n 元素列下标
*
* @param 若元素存在, 则返回删除后稀疏矩阵中非 0 元素个数, 否则返回NPOS
*/
int DeleteElem( TMatrix *const pMat, int m, int n )
{
///使用断言确保下标合法
assert( m >= && m < pMat->row && n >= && n < pMat->col ); int pos = ElemLocate( pMat, m, n ); ///该元素是否存在
if( pos == NPOS )
return NPOS; ///删除该位置上的元素以及记录
for( pos; pos < pMat->unul - ; ++pos )
{
pMat->tup[pos].m = pMat->tup[pos+].m;
pMat->tup[pos].n = pMat->tup[pos+].n;
pMat->tup[pos].elm = pMat->tup[pos+].elm;
} ///缩小内容占用
pMat->tup = (TTuple *)realloc( pMat->tup, sizeof(TTuple) * (pMat->unul - ) ); return --pMat->unul;
} /**
* @brief 将源稀疏矩阵复制到目标稀疏矩阵中
*
* @param pMatDest 指向目标稀疏矩阵
* @param pMatSrc 指向源稀疏矩阵
*
* @return 返回复制成功后目标稀疏矩阵中的非0元素数量
*/
int TMatrixCopy( TMatrix *const pMatDest, TMatrix *const pMatSrc )
{
if( pMatDest->tup )
free( pMatDest->tup ); ///源稀疏矩是否为空
if( pMatSrc->tup )
{ //不为空, 复制矩阵
pMatDest->tup = (TTuple *)calloc( pMatSrc->unul, sizeof(TTuple) * pMatSrc->unul );
assert( pMatDest->tup );
memcpy( pMatDest->tup, pMatSrc->tup, sizeof(TTuple) * pMatSrc->unul );
}
else pMatDest->tup = NULL; pMatDest->row = pMatSrc->row;
pMatDest->col = pMatSrc->col;
pMatDest->unul = pMatSrc->unul; return pMatDest->unul;
} /**
* @brief 从稀疏矩阵中获取下标为 m, n 元素的值
*
* @param pMat 指向待获取元素的稀疏矩阵
* @param m 元素所在位置的行下标
* @param n 元素所在位置的列下标
* @param pElm 接收数据元素的指针
*
* @return 返回该元素在稀疏矩阵中的位置
*
* @note 位置由 0 计起
*/
int Value( const TMatrix *const pMat, int m, int n, ElemType *pElm )
{
///使用断言确保下标合法
assert( m >= && m < pMat->row && n >= && n < pMat->col ); int pos = ElemLocate( pMat, m, n );
if( pos != NPOS )
{
*pElm = pMat->tup[pos].elm;
return pos;
}
else
{
*pElm = ;
return NPOS;
}
} /**
* @brief 对稀疏矩阵中的每个元素依次执行 func 函数
*
* @param pMat 指向待处理的稀疏矩阵
* @param func 回调函数
*
* @return void
*/
void ForEach( const TMatrix *const pMat, void (*func)(ElemType *pElm) )
{
int m = , n = , pos = , t = ; for( m = ; m < pMat->row; ++m )
for( n = ; n < pMat->col; ++n )
{
pos = ElemLocate( pMat, m, n ); if( pos != NPOS )
func( &pMat->tup[pos].elm );
else
func( &t );
}
} ///测试 /**
* @brief ForEach的回调函数, 若元素为 0 则输出'x', 否则正常输出
*/
void display( ElemType *pElm )
{
if( *pElm == )
putchar( 'x' );
else
printf( "%d", *pElm );
} int main()
{
///稀疏因子为 0.098 的二维数组
ElemType arrMat[][] = {
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , },
{, , , , , , , , , , , , , , }
}; ///测试 CreateTMatirxFrom2DArray
///从二维数组 arrMat 中创建稀疏矩阵
TMatrix *pMat = CreateTMatirxFrom2DArray( arrMat, , );
printf( "稀疏矩阵占用空间大小: %d (byte)\n", GetTMatrixSize(pMat) ); ///测试 CreateEmptyTMatrix
///创建一个 5 x 5 大小的稀疏矩阵
TMatrix *pMat2 = CreateEmptyTMatrix( , ); ///测试 TMatrixCopy
///将 pMat 复制到 pMat2
TMatrixCopy( pMat2, pMat ); ///测试 DisplayTMatrix
printf( "输出稀疏矩阵 pMat2:\n" );
DisplayTMatrix( pMat2 ); ///测试 AppendElem
printf( "将 0, 0 处元素置为 1.\n" );
AppendElem( pMat2, , , ); ///测试 DeleteElem
printf( "删除 0, 1 处的元素.\n" );
DeleteElem( pMat2, , ); ///输出 pMat2
printf( "输出稀疏矩阵 pMat2:\n" );
DisplayTMatrix( pMat2 ); ///测试 Value
int a = -;
Value( pMat2, , , &a );
printf( "位置 10, 8 处的元素为: %d\n", a ); ///测试 ForEach
printf( "将稀疏矩阵中值为0的元素用x代替并全部输出:\n" );
ForEach(pMat2, display ); ///销毁稀疏矩阵
DestroyTMatrix( pMat );
DestroyTMatrix( pMat2 ); return ;
}

运行测试:

若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢。                                                                                                                                                                                                                                                                                                                                                       

C语言 稀疏矩阵 压缩 实现的更多相关文章

  1. C语言 对称矩阵 压缩 实现

    对称矩阵压缩的简单实现 (GCC编译). /** * @brief C语言 对称矩阵 压缩 实现 * @author wid * @date 2013-11-03 * * @note 若代码存在 bu ...

  2. C语言Huffman压缩和解压

    符号表结构体: struct node { // 字符串形式存储的Huffman编码 char code[MAX_CODE_LENGTH]; // 这个字符在文件中出现的次数 long count; ...

  3. java实现稀疏矩阵的压缩与解压

    任务要求 把棋盘当作一个稀疏矩阵,0表示没棋,1表示黑棋,2表示蓝棋. 把该稀疏矩阵压缩以三元组形式表示并以文件形式保存,再写另一个程序读取文件中的信息把压缩后的三元组还原成原来的稀疏矩阵. 其中三元 ...

  4. C# .NET 使用第三方类库DotNetZip解压/压缩Zip rar文件

    DotNetZip on CodePlex: http://dotnetzip.codeplex.com/ 详细的可以看源代码……总之感觉比SharpZipLib好用.而且DotNetZip支持VB, ...

  5. 在Spark程序中使用压缩

    当大片连续区域进行数据存储并且存储区域中数据重复性高的状况下,数据适合进行压缩.数组或者对象序列化后的数据块可以考虑压缩.所以序列化后的数据可以压缩,使数据紧缩,减少空间开销. 1. Spark对压缩 ...

  6. C++ 特殊矩阵的压缩存储算法

    1. 前言 什么是特殊矩阵? C++,一般使用二维数组存储矩阵数据. 在实际存储时,会发现矩阵中有许多值相同的数据或有许多零数据,且分布呈现出一定的规律,称这类型的矩阵为特殊矩阵. 为了节省存储空间, ...

  7. OLAP了解与OLAP引擎——Mondrian入门

    一.  OLAP的基本概念 OLAP(On-Line Analysis Processing)在线分析处理是一种共享多维信息的快速分析技术:OLAP利用多维数据库技术使用户从不同角度观察数据:OLAP ...

  8. C++ 记事本: 从历史说起

    C 的简史 在谈论 C++ 的历史那么必须先得了解 C 的历史,那么我们先来看一段来自于 <<C专家编程>> 对 C 语言史前阶段的简单阐述: Ken Thompson(左), ...

  9. 算法设计手冊(第2版)读书笔记, Springer - The Algorithm Design Manual, 2ed Steven S.Skiena 2008

    The Algorithm Design Manual, 2ed 跳转至: 导航. 搜索 Springer - The Algorithm Design Manual, 2ed Steven S.Sk ...

随机推荐

  1. zabbix3.0.4监控mysql主从同步

    zabbix3.0.4监控mysql主从同步 1.监控mysql主从同步原理: 执行一个命令 mysql -u zabbix -pzabbix -e 'show slave status\G' 我们在 ...

  2. 开源GIS简介.学习

    开发者都希望自己的软件能够运行在尽可能多的计算机上.然而事与愿违,摆在 GIS开发者面前的仍然是对峙的平台.J2EE随着Java5.0的发布,已经正式更名为JavaEE,而微软也正式发布了.NET2. ...

  3. socket-自我总结(1)

    socket是个啥:我的总结如下: socket:针对服务器----客户端socket,进行打开,读写,管理的操作. socket也称套接字,IP跟端口.用来对两台服务器之间的通信的.一个IP跟端口, ...

  4. java的四种取整方法

    java 中取整操作提供了四种方法:分别是: public static double ceil(double a)//向上取整  public static double floor(double ...

  5. Spring 通过FactoryBean配置Bean

    1.实现FactoryBean接口 import org.springframework.beans.factory.FactoryBean; public class CarFactoryBean ...

  6. golang--gopher北京大会(1)

    大会感想:牛人真的很能写代码,实现很多功能,而且开源的精品越多,影响力越大,越能过上dream life.比如beego的作者,去了America,进入了Apple.另外,精英们特点是表达能力很强,也 ...

  7. UVA 753 A Plug for UNIX(二分图匹配)

    A Plug for UNIX You are in charge of setting up the press room for the inaugural meeting of the Unit ...

  8. Spark Streaming

    Spark Streaming Spark Streaming 是Spark为了用户实现流式计算的模型. 数据源包括Kafka,Flume,HDFS等. DStream 离散化流(discretize ...

  9. adb通信原理分析

    关于这个问题,自己研究了一下,没有研究出来 在网络上搜罗了一下,基本上关于ADB的原理用了两张图表示:        我表示没有看懂这两个图, 又开始查阅一些一些资料: 首先知道adb的通信有Sock ...

  10. Log4j基本用法

    基本使用方法: Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式.日志信息的优先级从高到低有ERROR.WARN.INFO.DEBUG,分别用来指定这条日志信 ...