实例19 矩阵的存储方法

难懂?

/**
* @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 > 0 && sizeN > 0 );

    TMatrix *pMat = (TMatrix *)malloc( sizeof(TMatrix) );
    pMat->tup = NULL;
    pMat->row = sizeM;
    pMat->col = sizeN;
    pMat->unul = 0;

    return pMat;
}

/**
* @brief 从二维数组中创建稀疏矩阵
*
* @param pArr2D 一个ElemType型二维数组
* @param sizeM 二维数组的行数
* @param sizeN 二维数组的列数
*
* @return 返回创建的稀疏矩阵的指针
*/
TMatrix *CreateTMatirxFrom2DArray( void *pArr2D, int sizeM, int sizeN )
{
    ///不接受大小为0的稀疏矩阵
    assert( sizeM > 0 && sizeN > 0 );

    TMatrix *pMat = (TMatrix *)malloc( sizeof(TMatrix) );

    ///初始化稀疏矩阵行数、列数
    pMat->row = sizeM;
    pMat->col = sizeN;

    ///第一趟遍历, 统计非零元素个数
    int m = 0, n = 0;
    for( m = 0; m < sizeM; ++m )
        for( n = 0; n < sizeN; ++n )
            if( ((ElemType *)pArr2D)[sizeM * m + n] != 0 )
                ++pMat->unul;

    ///申请合适长度的三元组类型的线性表
    pMat->tup = (TTuple *)calloc( pMat->unul, sizeof(TTuple) );

    ///第二趟遍历, 存储二维矩阵中的非零元素
    int nPos = 0;
    for( m = 0; m < sizeM; ++m )
        for( n = 0; n < sizeN; ++n )
            if( ((ElemType *)pArr2D)[sizeM * m + n] != 0 )
            {
                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 = 0;
    for( i = 0; 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 = 0, n = 0, pos = 0;
    for( m = 0; m < pMat->row; ++m )
    {
        for( n = 0; n < pMat->col; ++n )
        {
            pos = ElemLocate( pMat, m, n );
            if( pos != NPOS )
                printf( "%d ",  pMat->tup[pos].elm );
            else
                printf( "%d ", 0 );
        }
        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 >= 0 && m < pMat->row && n >= 0 && n < pMat->col );

    ///断言元素值合法(不接受元素值为0的元素)
    assert( elm != 0 );

    ///测试下标是否存在
    int i = 0, pos = 0;
    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 + 1) );
    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 >= 0 && m < pMat->row && n >= 0 && n < pMat->col );

    int pos = ElemLocate( pMat, m, n );

    ///该元素是否存在
    if( pos == NPOS )
        return NPOS;

    ///删除该位置上的元素以及记录
    for( pos; pos < pMat->unul - 1; ++pos )
    {
        pMat->tup[pos].m = pMat->tup[pos+1].m;
        pMat->tup[pos].n = pMat->tup[pos+1].n;
        pMat->tup[pos].elm = pMat->tup[pos+1].elm;
    }

    ///缩小内容占用
    pMat->tup = (TTuple *)realloc( pMat->tup, sizeof(TTuple) * (pMat->unul - 1) );

    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 >= 0 && m < pMat->row && n >= 0 && n < pMat->col );

    int pos = ElemLocate( pMat, m, n );
    if( pos != NPOS )
    {
        *pElm = pMat->tup[pos].elm;
        return pos;
    }
    else
    {
        *pElm = 0;
        return NPOS;
    }
}

/**
* @brief 对稀疏矩阵中的每个元素依次执行 func 函数
*
* @param pMat 指向待处理的稀疏矩阵
* @param func 回调函数
*
* @return void
*/
void ForEach( const TMatrix *const pMat, void (*func)(ElemType *pElm) )
{
    int m = 0, n = 0, pos = 0, t = 0;

    for( m = 0; m < pMat->row; ++m )
        for( n = 0; 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 == 0 )
        putchar( 'x' );
    else
        printf( "%d", *pElm );
}

int main()
{
    ///稀疏因子为 0.098 的二维数组
    ElemType arrMat[15][15] = {
        {0, 9, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0},
        {0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 8, 0, 0},
        {0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 7, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0},
        {0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 8, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0},
        {0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0}
    };


    ///测试 CreateTMatirxFrom2DArray
    ///从二维数组 arrMat 中创建稀疏矩阵
    TMatrix *pMat = CreateTMatirxFrom2DArray( arrMat, 15, 15 );
    printf( "稀疏矩阵占用空间大小: %d (byte)\n", GetTMatrixSize(pMat) );

    ///测试 CreateEmptyTMatrix
    ///创建一个 5 x 5 大小的稀疏矩阵
    TMatrix *pMat2 = CreateEmptyTMatrix( 5, 5 );

    ///测试 TMatrixCopy
    ///将 pMat 复制到 pMat2
    TMatrixCopy( pMat2, pMat );

    ///测试 DisplayTMatrix
    printf( "输出稀疏矩阵 pMat2:\n" );
    DisplayTMatrix( pMat2 );

    ///测试 AppendElem
    printf( "将 0, 0 处元素置为 1.\n" );
    AppendElem( pMat2, 1, 0, 0 );

    ///测试 DeleteElem
    printf( "删除 0, 1 处的元素.\n" );
    DeleteElem( pMat2, 0, 1 );

    ///输出 pMat2
    printf( "输出稀疏矩阵 pMat2:\n" );
    DisplayTMatrix( pMat2 );

    ///测试 Value
    int a = -1;
    Value( pMat2, 10, 8, &a );
    printf( "位置 10, 8 处的元素为: %d\n", a );

    ///测试 ForEach
    printf( "将稀疏矩阵中值为0的元素用x代替并全部输出:\n" );
    ForEach(pMat2, display );

    ///销毁稀疏矩阵
    DestroyTMatrix( pMat );
    DestroyTMatrix( pMat2 );

	system("pause");
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值