数据结构(C/C++)课程阶段总结(七)

写在前面

课程采用教材《数据结构(C语言版)》严蔚敏,吴伟民,清华大学出版社。
本系列博文用于自我学习总结和期末复习使用,同时也希望能够帮助到有需要的同学。如果有知识性的错误,麻烦评论指出。
本次实验实现稀疏矩阵的三元组顺序存储表示。

稀疏矩阵抽象数据类型定义

本次实验中抽象数据类型定义如下:
ADT SparseMatrix {
数据对象:D={aij|i=1,2,…,m;j=1,2,…,n; aij∈ElemSet,m和n分别称为矩阵的行数和列数}
数据关系:R={Row,Col}
Row={<ai,j,ai,j+1>|1≤i≤m,1≤j≤n-1}
Col={<ai,j,ai+1,j>|1≤i≤m-1,1≤j≤n}
基本操作:
CreateTSMatrix(&TSMat, * S[],row, col)
初始条件:S为稀疏矩阵,row为行数,col为S的列数。
操作结果:用三元组表TSMat存储S,并返回OK。
ChangeValue(&TSMat, e, i, j)
初始条件:TSMat为稀疏矩阵,e为修改元素,i,j为修改位置。
操作结果:修改稀疏矩阵的i,j位置的元素为e。
GetValue(TSMat, &e,i,j)
初始条件:TSMat为稀疏矩阵,e为传出元素,i,j为元素位置。
操作结果:获取稀疏矩阵的i,j位置的元素并用e传出。
DispTSMat(TSMat)
初始条件:TSMat为稀疏矩阵。
操作结果:输出三元组表。
DispSMat(TSMat)
初始条件:TSMat为稀疏矩阵。
操作结果:输出稀疏矩阵。
}ADT SparseMatrix

基本操作的实现方法

稀疏矩阵的存储方式采用三元组顺序表存储。三元组表的结构体中,包含矩阵的行数、列数、非零元素个数和含有非零元素值及位置信息的三元组表。

稀疏矩阵对应三元组表的创建

目标:创建稀疏矩阵对应的三元组表。
具体过程:
为了增加程序的通用性,创建函数CreateTSMatrix(TSMatrix& TSMat, ElemType* S[], int row, int col)以指针数组的形式传入稀疏矩阵,避免使用预定义常量,来限制稀疏矩阵的大小,但需要传入稀疏矩阵的行数和列数。
将传入的行数和列数赋给三元组表,并将非零元素个数置零。按行主序遍历稀疏矩阵,将非零元素存入三元组表中,并将非零元素个数加1。

改变矩阵元素值

目标:改变稀疏矩阵中任意一个元素的值。
具体过程:
在原来非零元素改动到另一非零元素或零元素改动到非零元素的基础上,增加了非零元素改动到零元素的功能。
非零元素改到另一非零元素相对简单,而零元素改到非零元素应视为三元组表以行数递增为序,有序插入一个三元组,相反非零元素改到零元素应视为三元组表中删除对应的三元组。
程序中,先寻找到更改位置在三元组表中的位置,再判断该位置是否有非零元素,如果有,直接更改该位置元素值或执行删除操作即可,如果没有,需要执行有序插入操作。每次操作过后,需要更改非零元素个数。

获取矩阵元素值

目的:从三元组表中获取稀疏矩阵任意位置的元素值。
具体操作:
先获取查找位置在三元组表中的位置,再判断该位置是否有非零元素,如果有,直接传出该位置元素值即可,如果没有,则传出0。

输出矩阵

目标:分别输出稀疏矩阵的三元组表和矩阵
具体操作:
输出三元组表可参照顺序表的输出方式,输出矩阵需要判断循环位置的元素是在三元组表中,如果在,则输出三元组中的值,否则输出0。

具体实现

//1、用到的头文件、命名空间和函数执行结果状态代码
#include <iostream>
using namespace std;
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状况代码
typedef int Status;
typedef int ElemType;//将ElemType定义为int类型
//2、采用的存储结构
//-----稀疏矩阵的三元组顺序表存储表示-----
#define MAXSIZE 125 // 假设非零元个数的最大值为125
struct Triple {
	int  i,j;// 该非零元素的行下标和列下标
	ElemType e;// 该非零元素的值
};
struct TSMatrix {
	Triple data[MAXSIZE];// 非零元三元组表,data[0]使用
	int row, col, num;// 矩阵的行数、列数和非零元个数
};

//3、基本操作侧函数原型说明及实现
//-----基本操作的函数原型说明-----
Status CreateTSMatrix(TSMatrix& TSMat, ElemType* S[], int row, int col);
// 初始条件:S为稀疏矩阵,row为行数,col为S的列数。
// 操作结果:用三元组表TSMat存储S,并返回OK。
Status ChangeValue(TSMatrix& TSMat, ElemType e, int i, int j);
// 初始条件:TSMat为稀疏矩阵,e为修改元素,i,j为修改位置。
// 操作结果:修改稀疏矩阵的i,j位置的元素为e。
Status GetValue(TSMatrix TSMat, ElemType& e, int i, int j);
// 初始条件:TSMat为稀疏矩阵,e为传出元素,i,j为元素位置。
// 操作结果:获取稀疏矩阵的i,j位置的元素并用e传出。
void DispTSMat(TSMatrix TSMat);
// 初始条件:TSMat为稀疏矩阵。
// 操作结果:输出三元组表。
void DispSMat(TSMatrix TSMat);
// 初始条件:TSMat为稀疏矩阵。
// 操作结果:输出稀疏矩阵。
//-----基本操作的算法描述-----

Status CreateTSMatrix(TSMatrix& TSMat, ElemType* S[], int row, int col) {
	// 用三元组表TSMat存储S,并返回OK。
	TSMat.num = 0; TSMat.row = row; TSMat.col = col;// 非零元素数置零,获取稀疏矩阵的行列数
	for (int i = 0; i < row; i++)// 遍历稀疏矩阵行
		for (int j = 0; j < col; j++)// 遍历稀疏矩阵列
			if (*(S[i] + j))// 如果当前元素非零
			{// 取出当前元素的信息
				TSMat.data[TSMat.num].e = *(S[i] + j);// 元素值放入三元组
				TSMat.data[TSMat.num].i = i;// 元素行位置
				TSMat.data[TSMat.num].j = j;// 元素列位置
				TSMat.num++;// 非零元素个数加1
			}
	return OK;
}// CreateTSMatrix
Status ChangeValue(TSMatrix& TSMat, ElemType e, int i, int j) {
	// 修改稀疏矩阵的i,j位置的元素为e。
	int loc = 0;// 三元组顺序表位置置零
	if (i >= TSMat.row || j >= TSMat.col)return ERROR;// 判断修改位置的合法性
	while (TSMat.data[loc].i < i && loc < TSMat.num)loc++;// 遍历三元组中的行,直到修改位置的行数或表尾
	while (TSMat.data[loc].j < j && TSMat.data[loc].i == i && loc < TSMat.num)loc++;// 遍历三元组中的列,直到修改位置的列数或表尾
	if (TSMat.data[loc].i == i && TSMat.data[loc].j == j && e)// 如果修改位置元素且e不为0
		TSMat.data[loc].e = e;// 则修改此位置元素为e
	else if (e)// 如果修改位置元素为0但e不为0
	{// 则在三元组表的loc位置插入e
		for (int k = TSMat.num - 1; k >= loc; k--)// loc位置之后的元素整体后移一位
			TSMat.data[k + 1] = TSMat.data[k];// 结构体整体赋值
		TSMat.data[loc].i = i; TSMat.data[loc].j = j; TSMat.data[loc].e = e;// 插入e,及e在稀疏矩阵中的位置
		TSMat.num++;// 非零元素个数加1
	}
	else if (TSMat.data[loc].i == i && TSMat.data[loc].j == j)// 如果修改位置元素不为0但e为零
	{// 则删除三元组表的loc位置元素
		for (int k = loc; k < TSMat.num; k++)// loc位置之后的元素整体前移一位
			TSMat.data[k] = TSMat.data[k + 1];// 结构体整体赋值
		TSMat.num--;// 非零元素个数减1
	}
	return OK;
}// ChangeValue

Status GetValue(TSMatrix TSMat, ElemType& e, int i, int j) {
	// 获取稀疏矩阵的i,j位置的元素并用e传出。
	int loc = 0;// 三元组表位置初始为0
	if (i >= TSMat.row || j >= TSMat.col)return ERROR;// 判断查找位置的合法性
	while (loc < TSMat.num && TSMat.data[loc].i < i)loc++;// 遍历三元组中的行,直到查找位置的行数或表尾
	while (TSMat.data[loc].i == i && loc < TSMat.num && TSMat.data[loc].j < j)loc++;// 遍历三元组中的列,直到查找位置的列数或表尾
	if (TSMat.data[loc].i == i && TSMat.data[loc].j == j)// 如果查找位置元素不为零
		e = TSMat.data[loc].e;// 则传出查找位置元素的值
	else// 如果查找位置元素为0
		e = 0;// 则传出0
	return OK;
}// GetValue

void DispTSMat(TSMatrix TSMat) {
	// 输出三元组表。
	if (TSMat.num <= 0)return;
	cout << "稀疏矩阵行数:" << TSMat.row << " 列数:" << TSMat.col << " 非零元素总数:" << TSMat.num << "\n";
	cout << "行\t" << "列\t" << "元素\n";
	for (int i = 0; i < TSMat.num; i++)// 按顺序遍历三元组表
		cout << TSMat.data[i].i << "\t" << TSMat.data[i].j << "\t" << TSMat.data[i].e << "\n";
}// DispTSMat

void DispSMat(TSMatrix TSMat) {
	// 输出稀疏矩阵。
	if (TSMat.num <= 0)return;
	int loc=0;
	cout << "稀疏矩阵为:\n";
	for (int i = 0; i < TSMat.row; i++)// 遍历行
	{
		for (int j = 0; j < TSMat.col; j++)// 遍历列
		{
			if (TSMat.data[loc].i == i && TSMat.data[loc].j == j)// 如果当前位置元素不为0
				cout << TSMat.data[loc++].e << " ";// 则输出当前位置元素
			else cout << 0 << " ";// 否则输出0
		}cout << endl;// 一行遍历结束,换行
	}cout << endl;
}// DispSMat

int main()
{
	ElemType* S[10], e;
	for (int i = 0; i < 10; i++)// 创建10*10的矩阵,由10个一维数组组成
		S[i] = new ElemType[10];// 申请空间
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
			*(S[i]+j) = 0;// 全部赋0
	S[0][0] = 1;// 在(0,0)位置赋1
	S[4][3] = 2;// 在(4,3)位置赋2
	S[2][8] = 3;// 在(2,8)位置赋3
	TSMatrix TSMat;// 创建三元组顺序表
	CreateTSMatrix(TSMat, S, 10, 10);// 用三元组表存储稀疏矩阵
	DispTSMat(TSMat);// 输出三元组表
	DispSMat(TSMat);// 输出稀疏矩阵

	ChangeValue(TSMat, 8, 0, 0);// 修改(0,0)位置元素为8
	DispTSMat(TSMat);// 输出三元组表
	DispSMat(TSMat);// 输出稀疏矩阵

	ChangeValue(TSMat, 8, 9, 9);// 修改(9,9)位置元素为8
	DispTSMat(TSMat);// 输出三元组表
	DispSMat(TSMat);// 输出稀疏矩阵

	ChangeValue(TSMat, 4, 4, 4);// 修改(4,4)位置元素为4
	DispTSMat(TSMat);// 输出三元组表
	DispSMat(TSMat);// 输出稀疏矩阵

	ChangeValue(TSMat, 0, 4, 4);// 修改(4,4)位置元素为0
	DispTSMat(TSMat);// 输出三元组表
	DispSMat(TSMat);// 输出稀疏矩阵

	GetValue(TSMat, e, 0, 0);// 获取(0,0)位置元素
	cout <<"稀疏矩阵中("<<0<<","<<0<<")位置元素为:"<< e << endl;
}

运行结果

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

总结

实验中采用了指针数组的形式,创建稀疏矩阵,需要时刻注意数组越界和内存泄漏。而且需要注意的是,三元组表和稀疏矩阵的0位置也存储有值,如果从位置1开始存储,需要在合适的地方加减1。
稀疏矩阵是一类特殊矩阵。假设在m×n的矩阵中,有t个元素不为零。令 δ = t m × n \delta =\frac{t}{m\times n} δ=m×nt,称 δ δ δ为矩阵的稀疏因子。通常认为 δ ≤ 0.05 δ≤0.05 δ0.05时称为稀疏矩阵。在实际应用中,稀疏矩阵往往比较大,需要压缩存储,在本次实验中采用三元组顺序存储结构来压缩稀疏矩阵,并且稀疏矩阵的部分操作通过操作三元组表来实现。
为了增强程序的通用性,尽量减少使用预定义常量,稀疏矩阵的实现采用指针数组,指针数等于矩阵行数,每个指针申请的空间等于矩阵列数。对数组中的元素都先赋值0,再对具体的行列赋非零值。虽然矩阵的建立稍微麻烦了些,但增强了程序的通用性,这种操作在后面的实验中仍有尝试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kFkPkDkN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值