文章目录
1 数组定义与运算
数组的定义:
逻辑结构上,数组可以看做线性表的扩充。一维数组即为线性表,二维数组其数据元素为一维数组的线性表,以此类推,N维数组是数据元素为N-1维数组的线性表。
数组的运算:
- 获取特定位置的元素值
- 修改特定位置的元素值
2 数组的顺序存储与实现
对于数组而言,其维数和各维长度一旦确定,则该数组的元素个数就是确定的,并且数组的基本操作不涉及数组结构的变化,因此采用顺序存储更为合适。
数组的顺序存储结构有两种:
- 按行序存储
- 按列序存储
数组地址的计算方法(以按行序排序为例):
数组的地址计算 | 公式 |
---|---|
一维数组 | Loc(A[i]) = Loc(A[1]) + (i-1)*size |
二维数组 | Loc(A[i][j]) = Loc(A[1][1]) + ((i-1)*n+j-1)*size |
三维数组 | Loc(A[i][j][k]) = Loc(A[1][1][1]) + ((i-1)mn+(j-1)*n+k-1)*size |
3 特殊矩阵的压缩存储
3.1 规律分布的特殊矩阵
3.1.1 三角矩阵
三角矩阵大体分为:下三角矩阵、上三角矩阵和对称矩阵。
下三角矩阵如图:
对于下三角矩阵,其元素分布为a11,a21.a22,a31,a32,a33……ann,共有1+2+……+n=n(n+1)/2个元素,因此我们可以把下三角矩阵存储到一个大小为n(n+1)/2的一维数组中,其中元素a[i][j]在数组C中的存储位置为:Loc[i,j] = Loc[1,1] + ((i -1)*i/2+j-1)*size
同样,对于上三角矩阵,也可以将其压缩存储到一个大小为n(n+1)/2的一维数组中。其中元素a[i][j]在数组C中的存储位置为:Loc[i,j]= Loc[1,1]+(j*(j -1)/2+ i-1)*size
对于对称矩阵,因其元素满足a[i][j]=a[j][i],我们可以为每一对相等的元素分配一个存储空间,即只存下三角(或上三角)矩阵,从而将n*n个元素压缩到n(n+1)/2个空间中。
3.1.2 带状矩阵
在矩阵A中,所有的非零元素都集中在以主对角线为中心的带状区域中。最常见的是三对角带状矩阵
三对角带状矩阵特点:
- 当i=1,j=1,2
- 当i=n,j=n-1,n
- 当1<i<n,j = i-1,i,i+1
三对角带状矩阵的压缩存储方法:
- 确定存储该矩阵所需的一维向量的大小:3*n-2
- 确定非零元素在一维数组空间中的地址:Loc(A[i][j]) = Loc(A[1][1]) + (3*(i-1)-1+j-i+1)size = Loc(A[1][1]) + (2(I-1)+j-1)*size
3.2 稀疏矩阵
指矩阵中大多数元素为零的矩阵。一般地,当非零元素个数只占矩阵元素总数的25%—30%,或低于这个百分数时,我们称这样的矩阵为稀疏矩阵。
3.2.1 稀疏矩阵的三元组表表示方法
#define MAXSIZE 255
typedef struct
{
int row,col; //非零元素的行值和列值
int value; //非零元素的值
}Triple;
typedef struct
{
Triple data[MAXSIZE+1]; //data[0]未用
int m,n,len; //矩阵行数,列数和非零元素个数
}TSMatrix;
3.2.2 稀疏矩阵的转置
对于普通矩阵,我们只需要将其每个元素的行下标和列下标互换。但是对于用三元组表表示的稀疏矩阵,只把行下标和列下标互换是不够的。应归纳成以下三点:
- 每个元素的行下标和列下标互换
- 总行数m和总列数n互换
- 重排三元组内各元素顺序,使转置后的三元组也按行(或列)为主序有规律的排列。
方法一:列序递增转置法
扫描A中所有col为1的元素,转置后添加至B。以此类推。
代码如下:
void TransposeTSMatrix(TSMatrix A, TSMatrix *B) {
int i,j,k;
B->m = A.n;
B->n = A.m;
B->len = A.len;
if(B->len>0){
j = 1; //辅助计数器
for(k=1;k<=A.n;k++){
for(i=1;i<=A.len;i++)
{
if(A.data[i].col==k){
B->data[j].row = A.data[i].col;
B->data[j].col = A.data[i].row;
B->data[j].e = A.data[j].e;
j++;
}
}
}
}
}
方法二:一次定位快速转置法
设置两个数组num[]和position[],前者用来存放三元组表A第col列中非零元素总个数,后者存转置前三元组A第col列第一个非零元素在三元组表B中的存储位置(下标)
FastTransposeTSMatrix(TSMatrix A, TSMatrix * B){
int col,t,p,q;
B->len = A.len;
B->n = A.m;
B->m = A.n;
if(B->len){
for(col=1;col<=A.n;col++)
num[col] = 0;
for(t=1;t<=A.len;t++)
num[A.data[t].col]++; //采用数组下标计数法计算每一列非零元素个数
position[1] = 1;
for(col=2;col<=A.n;col++)
position[col] = positon[col-1] + num[col-1]; //求col列第一个非零元素在B.data[]中的正确位置
for(p=1;p<=A.len;p++){
col = A.data[p].col;
q = position[col];
B->data[q].row = A.data[p].col;
B->data[q].col = A.data[p].row;
B->data[q].e = A.data[p].e;
position[col]++;
}
}
}
4 实验题
列序递增算法代码:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
//矩阵结构化描述
typedef struct{
int row,col; //非零元素的行值和列值
int value; //非零元素的值
}Triple;
typedef struct{
Triple data[MAXSIZE+1]; //data[0]未用
int m,n,len; //矩阵行数,列数和非零元素个数
}TSMatrix;
//创建矩阵
void CreateTSMatrix(TSMatrix *A){
int i = 1; //data[0]未用 i表示计数器
printf("请输入矩阵的行数:");
scanf("%d",&A->m);
printf("请输入矩阵的列数:");
scanf("%d",&A->n);
printf("请输入矩阵元素(例如1,1,1):");
while(1){
scanf("%d,%d,%d", &A->data[i].row,&A->data[i].col,&A->data[i].value);
if(A->data[i].row == 0 && A->data[i].col == 0 && A->data[i].value == 0)
break;
i++;
A->len++;
}
}
//稀释矩阵的转置的列序递增算法
void TransposeTSMatrix(TSMatrix A, TSMatrix *B) {
int i,j,k;
B->m = A.n;
B->n = A.m;
B->len = A.len;
if(B->len>0){
j = 1; //辅助计数器
for(k=1;k<=A.n;k++){
for(i=1;i<=A.len;i++)
{
if(A.data[i].col==k){
B->data[j].row = A.data[i].col;
B->data[j].col = A.data[i].row;
B->data[j].value = A.data[i].value;
j++;
}
}
}
}
}
//矩阵打印
void printTSMatrix(TSMatrix *A){
for(int i=1;i<=A->len;i++){
printf("(%d,%d,%d)\n",A->data[i].row,A->data[i].col,A->data[i].value);
}
}
//主函数
int main(){
TSMatrix A;
TSMatrix B;
A.m = 0;
A.n = 0;
A.len = 0;
CreateTSMatrix(&A);
TransposeTSMatrix(A,&B);
//打印原矩阵和新矩阵
printf("原矩阵:\n");
printTSMatrix(&A);
printf("新矩阵:\n");
printTSMatrix(&B);
return 0;
}
结果如下:
快速转置法代码:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
//矩阵结构化描述
typedef struct
{
int row,col; //非零元素的行值和列值
int value; //非零元素的值
}Triple;
typedef struct
{
Triple data[MAXSIZE+1]; //data[0]未用
int m,n,len; //矩阵行数,列数和非零元素个数
}TSMatrix;
//创建矩阵
void CreateTSMatrix(TSMatrix *A){
int i = 1; //data[0]未用 i表示计数器
printf("请输入矩阵的行数:");
scanf("%d",&A->m);
printf("请输入矩阵的列数:");
scanf("%d",&A->n);
printf("请输入矩阵元素(例如1,1,1):");
while(1){
scanf("%d,%d,%d", &A->data[i].row,&A->data[i].col,&A->data[i].value);
if(A->data[i].row == 0 && A->data[i].col == 0 && A->data[i].value == 0)
break;
i++;
A->len++;
}
}
//稀释矩阵的转置的快速转置方法
FastTransposeTSMatrix(TSMatrix A, TSMatrix *B){
int col,t,p,q;
int num[MAXSIZE],position[MAXSIZE];
B->len = A.len;
B->n = A.m;
B->m = A.n;
if(B->len){
for(col=1;col<=A.n;col++)
num[col] = 0;
for(t=1;t<=A.len;t++)
num[A.data[t].col]++; //采用数组下标计数法计算每一列非零元素个数
position[1] = 1;
for(col=2;col<=A.n;col++)
position[col] = position[col-1] + num[col-1]; //求col列第一个非零元素在B.data[]中的正确位置
for(p=1;p<=A.len;p++){
col = A.data[p].col;
q = position[col];
B->data[q].row = A.data[p].col;
B->data[q].col = A.data[p].row;
B->data[q].value = A.data[p].value;
position[col]++;
}
}
}
//矩阵打印
void printTSMatrix(TSMatrix *A){
for(int i=1;i<=A->len;i++){
printf("(%d,%d,%d)\n",A->data[i].row,A->data[i].col,A->data[i].value);
}
}
//主函数
int main(){
TSMatrix A;
TSMatrix B;
A.m = 0;
A.n = 0;
A.len = 0;
CreateTSMatrix(&A);
FastTransposeTSMatrix(A,&B);
//打印原矩阵和新矩阵
printf("原矩阵:\n");
printTSMatrix(&A);
printf("新矩阵:\n");
printTSMatrix(&B);
return 0;
}
结果如下: