数据结构-稀疏矩阵-实验报告与代码
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一.需求分析
输入要求:稀疏矩阵的行、列和非零元素个数
输出要求:稀疏矩阵的转置、加法、减法、乘法
二.算法设计
本程序中采用的数据模型,用到的抽象数据类型的定义,程序的主要算法流程及各模块之间的层次调用关系
1.抽象数据类型:
ADT List {
数据对象:D={ai:|ai∈ElemSet,i=1…n,n≥0}
数据关系:R={Row,Col}
Row={<ai,j,ai,j>|1<=i<=m,1<=j<=n-1}
Col={<ai,j,ai,j>|1<=i<=m-1,1<=j<=n}
基本操作:
Status CreateSMatrix(TSMatrix &M)
操作结果:初始化稀疏数组
void PrintSMatrix(TSMatrix M)
初始条件:稀疏数组M已经存在
操作结果:打印矩阵M
void DestroySMatrix(TSMatrix &M)
初始条件:稀疏数组M已经存在
操作结果:销毁矩阵M
void CopySMatrix(TSMatrix M, TSMatrix &T)
初始条件:稀疏数组M已经存在
操作结果:复制矩阵M到T
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
初始条件:稀疏数组M、N已经存在
操作结果:求矩阵的和Q=M+N
Status SubSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
初始条件:稀疏数组M、N已经存在
操作结果:求矩阵的差Q=M-N
Status TransposeSMatrix(TSMatrix M, TSMatrix & T)
初始条件:稀疏数组M已经存在
操作结果:求矩阵M的转置T
Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
初始条件:稀疏数组M已经存在
操作结果:求矩阵的积Q=M*N
}ADT List
2. 本程序有二个模块:
(1)主程序模块
main()
{
初始化;
{
接受命令;
显示结果;
}
}
(2)三元组表单元模块:实现矩阵抽象数据类型。
三.程序设计
根据算法设计中给出的有关数据和算法,选定物理结构,详细设计需求分析中所要求的程序。
包括:人机界面设计、主要功能的函数设计、函数之间调用关系描述等。
1、程序基本结构:
2、稀疏矩阵的三元组顺序表存储表示:
typedef struct { // 定义三元组的元素
int i, j;
int e;
} Triple;
typedef struct { // 定义普通三元组对象
Triple data[MAXSIZE + 1];
int mu, nu, tu;
} TSMatrix;
typedef struct { // 定义带链接信息的三元组对象Triple data[MAXSIZE + 2];
int rpos[MAXROW + 1];
int mu, nu, tu;
} RLSMatrix;
3、基本函数:
1)输入矩阵,按三元组格式输入
bool InPutTSMatrix(P & T, int y) {
cout << "输入矩阵的行,列和非零元素个数:" << endl;
cin >> T.mu >> T.nu >> T.tu;
cout << "请输出非零元素的位置和值:" << endl;
int k = 1;
for (; k <= T.tu; k++)
cin >> T.data[k].i >> T.data[k].j >> T.data[k].e;
return true;
}
2)输出矩阵,按标准格式输出
bool OutPutSMatrix(P T) {
int m, n, k = 1;
for (m = 0; m < T.mu; m++) {
for (n = 0; n < T.nu; n++) {
if ((T.data[k].i - 1) == m && (T.data[k].j - 1) == n) {
cout.width(4);
cout << T.data[k++].e;
} else {
cout.width(4);
cout << "0";
}
}
cout << endl;
}
return true;
}
3)求矩阵的转置矩阵
bool TransposeSMatrix() {
TSMatrix M, T; //定义预转置的矩阵
InPutTSMatrix(M, 0); //输入矩阵
int num[MAXROW + 1];
int cpot[MAXROW + 1]; //构建辅助数组
int q, p, t;
T.tu = M.tu;
T.mu = M.nu;
T.nu = M.mu;
if (T.tu) {
for (int col = 1; col <= M.nu; col++) num[col] = 0;
for (t = 1; t <= M.tu; t++) ++num[M.data[t].j];
cpot[1] = 1;
for (int i = 2; i <= M.nu; i++) cpot[i] = cpot[i - 1] + num[i - 1];
for (p = 1; p <= M.tu; p++) {
int col = M.data[p].j;
q = cpot[col];
T.data[q].i = col;
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
++cpot[col];
}
}
cout << "输入矩阵的转置矩阵为" << endl;
OutPutSMatrix(T);
return true;
}
4)两个矩阵相乘
bool MultSMatrix() {
RLSMatrix M, N, Q; // 构建三个带“链接信息”的三元组表示的数组InPutTSMatrix(M, 1); //用普通三元组形式输入数组
InPutTSMatrix(N, 1);
Count(M);
Count(N);
if (M.nu != N.mu) return false;
Q.mu = M.mu;
Q.nu = N.nu;
Q.tu = 0; //Q初始化
int ctemp[MAXROW + 1]; //辅助数组
int arow, tp, p, brow, t, q, ccol;
if (M.tu * N.tu) { // Q是非零矩阵
for (arow = 1; aro w <= M.mu; aro w++) {
///memset(ctemp,0,N.nu);
for (int x = 1; x <= N.nu; x++)
ctemp[x] = 0;
Q.rpos[arow] = Q.tu + 1; // 当前行的首个非零元素在三元组中的位置为此行前所有非零元素+1
if (arow < M.mu) tp = M.rpos[arow + 1];
else tp = M.tu + 1;
for (p = M.rpos[aro w]; p < tp; p++) { // 对当前行每个
非零元素进行操作
brow = M.data[p].j; // 在N中找到i值也操作元素的j值相等的行
if (brow < N.mu) t = N.rpos[brow + 1];
else t = N.tu + 1;
for (q = N.rpos[brow]; q < t; q++) { // 对找出的行当每个非零元素进行操作
ccol = N.data[q].j;
ctemp[ccol] += M.data[p].e * N.data[q].e; //
将乘得到对应值放在相应的元素累加器里面
}
}
for (ccol = 1; ccol <= Q.nu; ccol++) // 对已经求出的累加器中的值压缩到Q中
if (cte mp[ccol]) {
if (++Q.tu > MAXSIZE) return false;
Q.data[Q.tu].e = ctemp[ccol];
Q.data[Q.tu].i = arow;
Q.data[Q.tu].j = ccol;
}
}
}
OutPutSMatrix(Q);
return true;
}
5)矩阵的加法
bool AddSMatrix() {
CrossList M, N; // 创建两个十字链表对象,并初始化
CreateSMatrix_OL(M);
CreateSMatrix_OL(N);
cout << "输入的两矩阵的和矩阵为:" << endl;
OLink pa, pb, pre, hl[MAXROW + 1]; //定义辅助指针,pa,pb分别为M,N当前比较的元素,pre为pa的前驱元素
for (int x = 1; x <= M.nu; x++) hl[x] = M.chead[x];
for (int k = 1; k <= M.mu; k++) { // 对M的每一行进行操作
pa = M.rhead[k];
pb = N.rhead[k];
pre = NULL;
while (pb) { // 把N中此行的每个元素取出,
OLink p;
if (!(p = (OLink) malloc(sizeof (OLNode)))) exit(0); // 开辟新节点,存储N中取出的元素
p->e = pb->e;
p->i = pb->i;
p->j = pb->j;
if (NULL == pa || pa->j > pb->j) { // 当M此行已经检查完或者pb因该放在pa前面
if (NULL == pre)
M.rhead[p->i] = p;
else
pre->right = p;
p->right = pa;
pre = p;
if (NULL == M.chead[p->j]) { // 进行列插入
M.chead[p->j] = p;
p->do wn = NULL;
} else {
p->do wn = hl[p->j]->down;
hl[p->j]->do wn = p;
}
hl[p->j] = p;
pb = pb->right;
} else
if ((NULL != pa) && pa->j < pb->j) { // 如果此时
的pb元素因该放在pa后面,则取以后的pa再来比较
pre = pa;
pa = pa->right;
} else
if (pa->j == pb->j) { // 如果pa,pb位于同一个位置上,则将值相加
pa->e += pb->e;
if (!pa->e) { // 如果相加后的和为0,则删除此节点,同时改变此元素坐在行,列的前驱元素的相应值
if (NULL == pre) // 修改行前驱元素值
M.rhead[pa->i] = pa->right;
else
pre->right = pa->right;
p = pa;
pa = pa->right;
if (M.chead[p->j] == p) M.chead[p->j] = hl[p->j] = p->down; // 修改列前驱元素值
else
hl[p->j]->do wn = p->do wn;
free(p);
pb = pb->right;
} else {
pa = pa->right;
pb = pb->right;
}
}
}
}
OutPutSMatrix_OL(M);
return true;
}
4、各模块间的关系:
四.测试与分析
1、测试结果
输入1选择矩阵倒置:
输入2选择矩阵的加法: main InPutTSMat rix TransposeSMa AddSMatrix MultSMatrix
OutPutSMatrix
输入3选择矩阵的乘法:2、分析与遇到的问题
1)创建稀疏矩阵时,不懂如何用三元组表示元素的输出;
2)需要注意矩阵运算中的特殊状况,
比如:
稀疏矩阵相加时,忘记对应元素相加为0时,在稀疏矩阵中不表示;矩阵相乘时,必须符合第一个矩阵的列数等于第二个矩阵的行数;矩阵相加时,第一个矩阵的行列数要和第二个矩阵的行列数相等;
附录:源代码
#include <iostream>
#include <iomanip>
using namespace std;
const int MAXSIZE = 100; // 定义非零元素的对多个数
const int MAXROW = 10; // 定义数组的行数的最大值
typedef struct {
int i, j;
int e;
} Triple; // 定义三元组的元素
typedef struct {
Triple data[MAXSIZE + 1];
int mu, nu, tu;
} TSMatrix; // 定义普通三元组对象
typedef struct {
Triple data[MAXSIZE + 2];
int rpos[MAXROW + 1];
int mu, nu, tu;
} RLSMatrix; // 定义带链接信息的三元组对象
typedef struct OLNode { // 定义十字链表元素
int i, j;
int e;
struct OLNode *right, *down; // 该非零元所在行表和列表的后继元素} OLNode, *OLink; // 定义十字链表元素
typedef struct { // 定义十字链表对象结构体
OLink *rhead, *chead;
int mu, nu, tu; // 系数矩阵的行数,列数,和非零元素个数
} CrossList; // 定义十字链表对象结构体
template <class P>
bool InPutTSMatrix(P & T, int y) { //输入矩阵,按三元组格式输入cout << "输入矩阵的行,列和非零元素个数:" << endl;
cin >> T.mu >> T.nu >> T.tu;
cout << "请输出非零元素的位置和值:" << endl;
int k = 1;
for (; k <= T.tu; k++)
cin >> T.data[k].i >> T.data[k].j >> T.data[k].e;
return true;
}
template <class P>
bool OutPutSMatrix(P T) {
int m, n, k = 1;
for (m = 0; m < T.mu; m++) {
for (n = 0; n < T.nu; n++) {
if ((T.data[k].i - 1) == m && (T.data[k].j - 1) == n) {
cout.width(4);
cout << T.data[k++].e;
} else {
cout.width(4);
cout << "0";
}
}
cout << endl;
}
return true;
}// 输出矩阵,按标准格式输出
bool TransposeSMatrix() {
TSMatrix M, T; //定义预转置的矩阵
InPutTSMatrix(M, 0); //输入矩阵
int num[MAXROW + 1];
int cpot[MAXROW + 1]; // 构建辅助数组
int q, p, t;
T.tu = M.tu;
T.mu = M.nu;
T.nu = M.mu;
if (T.tu) {
for (int col = 1; col <= M.nu; col++) num[col] = 0;
for (t = 1; t <= M.tu; t++) ++num[M.data[t].j];
cpot[1] = 1;
for (int i = 2; i <= M.nu; i++) cpot[i] = cpot[i - 1] + num[i - 1]; // 求出每一列中非零元素在三元组中出现的位置
for (p = 1; p <= M.tu; p++) {
int col = M.data[p].j;
q = cpot[col];
T.data[q].i = col;
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
++cpot[col];
}
}
cout << "输入矩阵的转置矩阵为" << endl;
OutPutSMatrix(T);
return true;
}// 求矩阵的转置矩阵
bool Count(RLSMatrix &T) {
int num[MAXROW + 1];
for (int col = 1; col <= T.mu; col++) num[col] = 0;
for (int col = 1; col <= T.tu; col++) ++num[T.data[col].i];
T.rpos[1] = 1;
for (int i = 2; i <= T.mu; i++) T.rpos[i] = T.rpos[i - 1] + num[i - 1]; // 求取每一行中非零元素在三元组中出现的位置
return true;
}
bool MultSMatrix() {
RLSMatrix M, N, Q; // 构建三个带“链接信息”的三元组表示的数组InPutTSMatrix(M, 1); // 用普通三元组形式输入数组
InPutTSMatrix(N, 1);
Count(M);
Count(N);
cout << "输入的两矩阵的乘矩阵为:" << endl;
if (M.nu != N.mu) return false;
Q.mu = M.mu;
Q.nu = N.nu;
Q.tu = 0; // Q初始化
int ctemp[MAXROW + 1]; // 辅助数组
int arow, tp, p, brow, t, q, ccol;
if (M.tu * N.tu) { // Q是非零矩阵
for (arow = 1; arow <= M.mu; arow++) {
///memset(ctemp,0,N.nu);
for (int x = 1; x <= N.nu; x++) // 当前行各元素累加器清零
ctemp[x] = 0;
Q.rpos[arow] = Q.tu + 1; // 当前行的首个非零元素在三元组中的位置为此行前所有非零元素+1
if (arow < M.mu) tp = M.rpos[arow + 1];
else tp = M.tu + 1;
for (p = M.rpos[arow]; p < tp; p++) { // 对当前行每个非零元素进行操作
brow = M.data[p].j; // 在N中找到i值也操作元素的j 值相等的行
if (brow < N.mu) t = N.rpos[brow + 1];
else t = N.tu + 1;
for (q = N.rpos[brow]; q < t; q++) { // 对找出的行当每个非零元素进行操作
ccol = N.data[q].j;
ctemp[ccol] += M.data[p].e * N.data[q].e; // 将乘得到对应值放在相应的元素累加器里面
}
}
for (ccol = 1; ccol <= Q.nu; ccol++) // 对已经求出的累加器中的值压缩到Q中
if (ctemp[ccol]) {
if (++Q.tu > MAXSIZE) return false;
Q.data[Q.tu].e = ctemp[ccol];
Q.data[Q.tu].i = arow;
Q.data[Q.tu].j = ccol;
}
}
}
OutPutSMatrix(Q);
return true;
}// 两个矩阵相乘
bool CreateSMatrix_OL(CrossList & M) {
int x, y, m;
cout << "请输入矩阵的行,列,及非零元素个数" << endl;
cin >> M.mu >> M.nu >> M.tu;
if (!(M.rhead = (OLink*) malloc((M.mu + 1) * sizeof (OLink)))) exit(0);
if (!(M.chead = (OLink*) malloc((M.nu + 1) * sizeof (OLink)))) exit(0);
for (x = 0; x <= M.mu; x++)
M.rhead[x] = NULL; // 初始化各行,列头指针,分别为NULL for (x = 0; x <= M.nu; x++)
M.chead[x] = NULL;
cout << "请按三元组的格式输入数组:" << endl;
for (int i = 1; i <= M.tu; i++) {
cin >> x >> y >> m; // 按任意顺序输入非零元,(普通三元组形式输入)
OLink p, q;
if (!(p = (OLink) malloc(sizeof (OLNode)))) exit(0); // 开辟新节点,用来存储输入的新元素
p->i = x;
p->j = y;
p->e = m;
if (M.rhead[x] == NULL || M.rhead[x]->j > y) {
p->right = M.rhead[x];
M.rhead[x] = p;
} else {
for (q = M.rhead[x]; (q->right) && (q->right->j < y); q = q->right); // 查找节点在行表中的插入位置
p->right = q->right;
q->right = p; // 完成行插入
}
if (M.chead[y] == NULL || M.chead[y]->i > x) {
p->down = M.chead[y];
M.chead[y] = p;
} else {
for (q = M.chead[y]; (q->down) && (q->down->i < x); q = q->down); // 查找节点在列表中的插入位置
p->down = q->down;
q->down = p; // 完成列插入
}
}
return true;
}// 创建十字链表
bool OutPutSMatrix_OL(CrossList T) { // 输出十字链表,用普通数组形式输出
for (int i = 1; i <= T.mu; i++) {
OLink p = T.rhead[i];
for (int j = 1; j <= T.nu; j++) {
if ((p) && (j == p->j)) {
cout << setw(3) << p->e;
p = p->right;
} else
cout << setw(3) << "0";
}
cout << endl;
}
return true;
}//输出十字链表
bool AddSMatrix() {
CrossList M, N; // 创建两个十字链表对象,并初始化
CreateSMatrix_OL(M);
CreateSMatrix_OL(N);
cout << "输入的两矩阵的和矩阵为:" << endl;
OLink pa, pb, pre, hl[MAXROW + 1]; //定义辅助指针,pa,pb分别为M,N当前比较的元素,pre为pa的前驱元素
for (int x = 1; x <= M.nu; x++) hl[x] = M.chead[x];
for (int k = 1; k <= M.mu; k++) { // 对M的每一行进行操作
pa = M.rhead[k];
pb = N.rhead[k];
pre = NULL;
while (pb) { // 把N中此行的每个元素取出,
OLink p;
if (!(p = (OLink) malloc(sizeof (OLNode)))) exit(0); // 开辟新节点,存储N中取出的元素
p->e = pb->e;
p->i = pb->i;
p->j = pb->j;
if (NULL == pa || pa->j > pb->j) { // 当M此行已经检查完或者pb因该放在pa前面
if (NULL == pre)
M.rhead[p->i] = p;
else
pre->right = p;
p->right = pa;
pre = p;
if (NULL == M.chead[p->j]) { // 进行列插入
M.chead[p->j] = p;
p->down = NULL;
} else {
p->down = hl[p->j]->down;
hl[p->j]->down = p;
}
hl[p->j] = p;
pb = pb->right;
} else
if ((NULL != pa) && pa->j < pb->j) { // 如果此时的pb 元素因该放在pa后面,则取以后的pa再来比较
pre = pa;
pa = pa->right;
} else
if (pa->j == pb->j) { // 如果pa,pb位于同一个位置上,则将值相加
pa->e += pb->e;
if (!pa->e) { // 如果相加后的和为0,则删除此节点,同时改变此元素坐在行,列的前驱元素的相应值
if (NULL == pre) // 修改行前驱元素值
M.rhead[pa->i] = pa->right;
else
pre->right = pa->right;
p = pa;
pa = pa->right;
if (M.chead[p->j] == p) M.chead[p->j] = hl[p->j] = p->down; // 修改列前驱元素值
else
hl[p->j]->down = p->down;
free(p);
pb = pb->right;
} else {
pa = pa->right;
pb = pb->right;
}
}
}
}
OutPutSMatrix_OL(M);
return true;
}//矩阵的加法
int main() {
cout.fill('*');
cout << setw(80) << '*';
cout.fill(' ');
// system("color 0C");
cout << setw(50) << "***欢迎使用矩阵运算程序***" << endl; //输出头菜单
cout.fill('*');
cout << setw(80) << '*';
cout.fill(' ');
cout << " 请选择要进行的操作:" << endl;
cout << " 1:矩阵的转置。
" << endl;
cout << " 2:矩阵的加法。
" << endl;
cout << " 3:矩阵的乘法。
" << endl;
cout << " 4:退出程序。
" << endl;
printf("请输入您的选择:");
char c = getchar();
if (c == '1')
TransposeSMatrix(); //调用矩阵转置函数
else
if (c == '2')
AddSMatrix(); //调用矩阵相加函数
else
if (c == '3')
MultSMatrix(); //调用矩阵相乘函数
else
exit(0); //退出
return 0;
}。