数据结构与算法: 特殊矩阵的压缩存储

什么是矩阵?

在这里插入图片描述

什么是压缩存储?

在这里插入图片描述


一.对称矩阵的压缩存储:

在这里插入图片描述

  • 样式
    在这里插入图片描述

  • 储存方式图示:
    在这里插入图片描述

  • 对称矩阵的存储结构:
    在这里插入图片描述* 对称矩阵的压缩存储实现:

#include <stdio.h>
#include <stdlib.h>
#define M 10
#define N 4
int main()
{
    int a[M]={1,2,3,4,5,6,7,8,9,10};
    int b[M]={1,1,1,1,1,1,1,1,1,1};
    int c[N][N],d[N][N];
    int i,j,k=0,s;
    for(i=0;i<N;i++)
        for(j=0;j<=i;j++)
        {
            c[i][j]=a[k];
            d[i][j]=b[k];
            k++;
        }
    for(i=0;i<N-1;i++)
        for(j=i+1;j<N;j++)
        {
            c[i][j]=c[j][i];
            d[i][j]=d[j][i];
        }
    printf("1、输出对称矩阵M:\n");
    for(i=0;i<N;i++)
    {
        for(j=0;j<N-1;j++)
            printf("%d ",c[i][j]);
        printf("%d\n",c[i][j]);
    }
    printf("2、输出对称矩阵N:\n");
    for(i=0;i<N;i++)
    {
        for(j=0;j<N-1;j++)
            printf("%d ",d[i][j]);
        printf("%d\n",d[i][j]);
    }
    printf("3、两个对称矩阵M、N的和为:\n");
    for(i=0;i<N;i++)
    {
        for(j=0;j<N-1;j++)
            printf("%d ",c[i][j]+d[i][j]);
        printf("%d\n",c[i][j]+d[i][j]);
    }
    printf("3、两个对称矩阵M、N的积为:\n");
    for(i=0;i<N;i++)
    {
        for(j=0;j<N-1;j++)
        {
            s=0;
            for(k=0;k<N;k++) s+=c[j][k]*d[k][j];
            printf("%d ",s);
        }
        s=0; for(k=0;k<N;k++) s+=c[j][k]*d[k][j];
        printf("%d\n",c[i][j]+d[i][j]);
    }
    return 0;
}

在这里插入图片描述


以下转载自 : https://blog.csdn.net/SWEENEY_HE/article/details/85956176

二.三角矩阵的压缩存储

以主对角线划分三角矩阵有下三角矩阵和上三角矩阵

下三角矩阵:矩阵(除主对角线)的上三角部分的值均为一个常数C或者0

上三角矩阵:与下三角矩阵相反

图示:(图中蓝色主对角线部分元素(一般情况)永远不都为一个常数或者0)

               

二.压缩原理:

根据上、下三角矩阵的特殊性(有一小半部分的元素都为一个常数C或者0)我们可以考虑将这一半的空间压缩到一个元素(多对一的映射),然后另一半的部分就类似对称矩阵一半部分的压缩存储了。

三.矩阵坐标[i,j]转换为一维数组下标K的方法:

1>下三角矩阵:

(1).首先考虑,非重复部分的存储,见图:

可以得出 k = i(i-1)/2+j-1

(2).重复部分只需一个元素即可,为不影响前面的存储,考虑放到所有非重复元素的后面即可, 由于前面部分总共的元素个数为:

n(1+n)/2(等差数列求和,每行元素逐级递增)又由于数组以0为起点,所以放到n(1+n)/2的位置即可。

总结:

k = i(i-1)/2+j-1 (i<=j)  

k = n(n+1)/2 (i>j)   

2>上三角矩阵

(1).先考虑非重复部分的存储,图示:

  

按行优先存储,矩阵中元素对应一维数组的元素规则为:

由图显而易见,某元素在一维数组中的下标就是它按行优先存储时在半个矩阵中的序号

(1-1)序号 = 所有在它前面元素的个数 = 它所在行前面行的所有元素+它所在行它前面的元素

由于每行元素个数逐级递减,构成一个等差数列,公差:d = 1,首项:a1 = n ,末项:an = n-(i-1) = n-i+1(经评论区提醒,已自纠)

(1-2)前i-1行元素个数为:sn = n(a1+an)/2 = (i-1){n+[n-(i-1)+1]}/2=(i-1)(2n-i+2)/2  

(1-3)第i行中在它前面的元素个数为:j-1

(1-4)公式:K =(i-1)(2n-i+2)/2+j-1

(2).考虑重复部分元素和下三角一样:k = n(n+1)/2

总结:

K = (i-1)(2n-i+2)/2+j-i-1 (i<=j)

K = n(n+1)/2 (i>j)

  • 三角矩阵压缩存储代码实现:
#include<stdio.h>

int main() {

    int a[5][5] = {           //定义原二维数组

           1,0, 0, 0, 0,

           5,9, 0, 0, 0,

           4,6, 8, 0, 0,

           2,3, 44,55,0,

           7,11,12,13,14

    };

    int b[30], x, y, k;

    printf("原二维数组:\n");    //输出原二维数组

    for (x = 0; x < 5; x++)

    {

        for (y = 0; y < 5; y++)

        {

            printf("%d", a[x][y]);

        }

        printf("\n");

    }

    printf("压缩后的一维数组:\n");

    int t = 0;

    for (int i = 0; i < 5; i++)        //将二维数组中非0值压缩至一维数组中

    {

        for (int j = 0; j < 5; j++)

        {

            if (i >= j)              //特殊矩阵,只压下三角的值

            {

                k = i * (i + 1) / 2 + j;          //二维数组和一维数组中原值的对应关系

                b[k] = a[i][j];

                t++;

            }

            else

                b[15] = 0;

        }

    }

    for (int l = 0; l < t; l++)      //输出一维数组

    {

        printf("%d", b[l]);

    }

    printf("\n");

    printf("输入要查询的行号 列号:");   //输出要查询的数据

    printf("\n");

    scanf("%d%d", &x, &y);

    printf("您查询的数据是:\n");

    if (x < y)         //如果上三角直接输出0

        printf("0\n");

    else           //下三角输出一维数组中对应的值

        printf("%d\n", b[(x - 1) * (x) / 2 + y - 1]);

    return 0;

}

三. 对角矩阵的压缩存储:

在这里插入图片描述


存储方法:

在这里插入图片描述二维数组存储


所有非主对角线元素全等于零的n阶矩阵,称为对角矩阵或称为对角方阵。

在这里插入图片描述


对称矩阵压缩存储代码实现:

#include "stdio.h"
#define n 4
int d[n];
void Store(int x, int i, int j)
{/* 把x存为D ( i , j ) */
	if (i<0||j<0||i>=n||j>=n)
	{
		printf("数组出界!");
		exit(1);
	}
	if (i != j && x != 0)
	{
		printf("非对角线上元素值必须为零");
		exit(1);
	}
	if (i == j)
		d[i] = x; 	
}
void main()
{
	int i,j;
	int D[n][n] ={{2,0,0,0},{0,1,0,0},{0,0,4,0},{0,0,0,6}};
	for(i=0;i<n;i++)
		for(j=0;j<n;j++)
			Store(D[i][j],i,j);
	for(i=0;i<n;i++)
	   printf("%d  ",d[i]);
  printf("\n");
}

四. 稀疏矩阵的压缩存储:

在这里插入图片描述
三元组(i , j ,aij)唯一确定矩阵的一个非零元=


三元组顺序表:

在这里插入图片描述
三元顺序表的优缺点:

在这里插入图片描述


稀疏矩阵的链式存储结构 (十字链表)

优点:它能够灵活地插入因运算而产生的新的非零元素,删除因运算而产生的新的零元素,实现矩阵的运算。

在十字链表中,矩阵的每一个非零元素用一个结点表示,该结点除了(row,col,value)外,还有两个域:

right: 用于链接同一行中的下一个非零元素;

down:用以链接同一列中的下一个非零元素。

十字链表中结点的结构示意图:

在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/haduwi/article/details/106757784