数据结构实验——压缩矩阵的转置

Spraing※boy该实验中的难点是创建矩阵时,按照行序递增的输入顺序的控制,以及矩阵的快速转置,重点是掌握矩阵转置的算法。在做这次实验中,我也参照了很多代码,根据自己的理解和补充,我在代码部分加了很多的注释,希望各位学习的友友们可以借鉴学习❀❀。

实验题目:

用三元组表压缩存储矩阵,实现创建矩阵、显示以及两种转置算法。

(1)参考界面:

        1.创建矩阵

        2.销毁矩阵

        3.输出矩阵

        4.转置矩阵

        5.快速转置矩阵

(2)验收/测试用例

  1. 创建矩阵:

注意:检查非零元素个数是否小于等于行数乘列数;检查是否能拦截元素下标重复输入;检查是否能控制输入的非零元素的下标是递增的(即按照行序输入,先输入小的下标,再输入较大的下标)。

注意:输入的过程中如果有一个输入错了,不要让用户从头再把所有的输入一次,只需把刚才输入错误的,重新输入正确即可。

  1. 输入:4(行数) 4(列数) 25(非零元个数),会提示:输入错误,非零元素个数要小于等于行数乘列数,请从新输入。
  2. 输入:4(行数) 4(列数) 5(非零元个数)
  3. 先输入:(1,1,1) (2,3,2)
  4. 再输入(2,3,6),会提示:输入错误,输入的下标重复,请重新输入!
  5. 再输入(1,1,6),会提示:输入错误,输入的下标重复,请重新输入!
  6. 继续输入(3,1,3) (3,4,5)
  7. 再输入(3,2,9),会提示:输入错误,下标输入时要递增输入,请重新输入!
  8. 再输入(2,3,8),会提示:输入错误,下标输入时要递增输入,请重新输入!
  9. 最后输入(4,2,4)
  1. 显示

屏幕上输出

             1  0  0  0

             0  0  2  0

             3  0  0  5

             0  4  0  0

  1. 转置

屏幕上输出

             1  0  3  0

             0  0  0  4

             0  2  0  0

             0  0  5  0


#define MAXSIZE 12500 //假设非零元个数最大值为12500 
typedef struct {
 	int i, j;         //非零元的行下标和列下标
 	ElemType e;
 } Triple; 
 
 typedef struct {
 	Triple data[MAXSIZE+1];  /非零元三元组表,data[0]未使用
	int rows, cols, numbers; //矩阵的行数、列数、非零元个数 
 } TSMatrix; 

代码实现:

#include <bits/stdc++.h>
using namespace std;

#define MAXSIZE 12500 //表示非零元个数最大值 
typedef int ElemType; //存储元素的数据类型
bool isInit = false; //矩阵是否已经被创建的标记 
 
//三元组定义区
 typedef struct {
 	int i, j;
 	ElemType e;
 } Triple; 
 
 typedef struct {
 	Triple data[MAXSIZE+1];
	int rows, cols, numbers; //矩阵的行数、列数、非零元个数 
 } TSMatrix; 
 
//函数声明区 
void menu(); //功能菜单 
void CreateMatrix (TSMatrix &T); //创建矩阵 
void DestoryMatrix (TSMatrix T); //销毁矩阵 
void OutputMatrix (TSMatrix T); //输出矩阵 
void TransposeMatrix (TSMatrix T, TSMatrix &M); //矩阵的转置 
void FastTransposeMatrix (TSMatrix T, TSMatrix &M); //快速转置矩阵 
 
int main(){
	TSMatrix TSM, M; 
	int option = 0;
	menu();
	while (option >= 0){
		cout << "请输入你的选择:" << endl;
		cin >> option;
		if (option != 1 && option > 0 && isInit == false){
			cout << "你还未创建矩阵,请先创建矩阵" << endl;
			continue;
		} 
		switch(option) {
			case 1:
				CreateMatrix(TSM);
				break;
			case 2:
				DestoryMatrix(TSM);
				break; 
			case 3:
				cout << "输出矩阵:" << endl; 
				OutputMatrix(TSM);
				break;
			case 4:
				TransposeMatrix(TSM,M);
				cout << "转置之后的矩阵是:" << endl; 
				OutputMatrix(M); 
				break; 
			case 5:
				FastTransposeMatrix (TSM, M);
				cout << "快速转置之后的矩阵为:" << endl;
				OutputMatrix(M); 
				break;	
			default:
				cout << "成功退出,欢迎你下次使用!" << endl; 
				break;	
		}
	}
} 

//功能菜单 
void menu(){
	cout << "~~~~~~Spraing※boy~~~~~~~" << endl;
	cout << "**     1.创建矩阵      **" << endl;
	cout << "**     2.销毁矩阵      **" << endl;
	cout << "**     3.输出矩阵      **" << endl;
	cout << "**     4.转置矩阵      **" << endl;
	cout << "**     5.快速转置矩阵  **" << endl;
	cout << "**  ->退出输入一个负数 **" << endl; 
	cout << "~~~~~~~~~~~~~~~~~~~~~~~~~" << endl; 
} 

//创建矩阵
void CreateMatrix (TSMatrix &T){
	while (true){
		cout << "请输入总行数:" << endl;
		cin >> T.rows;
		if (T.rows <= 0){
			cout << "你的输入有误,请重新输入" << endl; 
		} else {
			break;
		}
	} 
	while (true){
		cout << "请输入总列数:" << endl;
		cin >> T.cols;
		if (T.cols <= 0){
			cout << "你的输入有误,请重新输入" << endl; 
		} else {
			break;
		}
	} 
	//矩阵输入的合法性的检查
	while (true){
		cout << "请输入总元素个数:" << endl;
		cin >> T.numbers;
		if (T.numbers <= 0){
			cout << "元素个数输入有误,请重新输入" << endl;
		}
		if (T.numbers > T.rows*T.cols){
			cout << "输入错误,非零元素个数要小于等于行数乘列数,请重新输入" << endl; 
		} else {
			break;
		} 	
	} 
	cout << "矩阵的行数为:" << T.rows << " 矩阵的列数为:" << T.cols << " 矩阵的非零元的个数为:" << T.numbers << endl; 
	int cnt = 1; //记录已插入的合法元素的个数 
	//定义三个变量分别代表输入的行,列,非零元素的值,如果在下面非法性的判断的过程中,结果合法,在对三元组相应属性赋值存储,如果非法让用户重新输入 
	int m, n, t; 
	while (cnt <= T.numbers){
		bool flag = true; //插入元素的合法性标记,必须放到while循环里面,不然会影响元素的存储,导致一些合法元素无法存入 
		cout << "请输入元素的行,列和非零元的值:(元素下标不能重复,且下标需要递增)" << endl;
		cin >> m >> n >> t;
		for (int b = 1; b <= cnt; ++b){
			//非法条件1:输入下标重复 
			if (T.data[b].i == m && T.data[b].j == n){
				cout << "输入错误,你输入的下标重复" << endl;
				flag = false;
				break;
			} else if (m <= 0 || n <= 0 || m > T.rows || n > T.cols){ //非法错误2:输入下标越界 
				cout << "输入错误,你输入的下标越界" << endl;
				flag = false;
				break;
			} else if (t == 0){ //非法错误3:输入元素为0 
				cout << "输入错误,你输入的非零元的值为0" << endl; 
				flag = false; 
				break;
			//非法错误4:输入下标行的时候不递增(只在输入非第一个元素的时候出现)
			//这里只需要判断上一个输入的行下表是否小于该次输入的下标,而上一个元素的行标已经储存到三元组对应位置中 
			} else if (cnt > 1 && T.data[cnt-1].i > m){ 
				cout << "输入错误,你输入时行的下标要逐渐递增" << endl;
				flag = false; 
				break;
			} else if (cnt > 1 && T.data[cnt-1].j > n && T.data[cnt-1].i == m){ //非法错误5:输入下标列的时候不递增 
				cout << "输入错误,你输入时列的下标要逐渐递增" << endl;
				flag = false; 
				break;
			}
		} 
		//输入合法元素 
		if (flag == true) {
			T.data[cnt].i = m;
			T.data[cnt].j = n;
			T.data[cnt].e = t;
			cout << "成功输入第" << cnt << "个元素," << "还有" << T.numbers-cnt << "个等待你的输入!" << endl;  
			cnt++; 
		} 
	}
	isInit  = true;
} 

//销毁矩阵 
void DestoryMatrix (TSMatrix T){
	for (int i = 0; i < T.numbers; ++i){
		T.data[i].e = 0; 
	}
	T.rows = T.cols = T.numbers = 0;
	cout << "矩阵销毁成功!" << endl;
	isInit = false;
} 

//输出矩阵
void OutputMatrix (TSMatrix T) {
	for (int i = 1; i <= T.rows; ++i){
		for (int j = 1; j <= T.cols; ++j){
			bool flag_isZero = true; //判断遍历矩阵时,是否为非零元,该标记必须放到循环体里面,每次判断结束都要初始化 
			for (int m = 1; m <= T.numbers; ++m){ //该层循环是为了遍历矩阵中非零元的所有下标 
				if (T.data[m].i == i && T.data[m].j == j){
					cout << T.data[m].e << "  ";
					flag_isZero = false;  
					break; 
				}
			}
			if (flag_isZero) {
				cout << "0" << "  "; 
			}
		}
		cout << endl; //一行元素输出完成之后换行 
	}
} 

//转置矩阵
void TransposeMatrix (TSMatrix T, TSMatrix &M) {
	M.rows = T.cols;
	M.cols = T.rows;
	M.numbers = T.numbers;
	if (M.numbers != 0){
		int cnt = 1; //通过cnt对三元组进行遍历 
		for (int i = 1; i <= T.cols; ++i){ //控制列数 
			for (int j = 1; j <= T.numbers; ++j){ //遍历T中的非零元 
				if (T.data[j].j == i){
					M.data[cnt].i = T.data[j].j;
					M.data[cnt].j = T.data[j].i;
					M.data[cnt].e = T.data[j].e;
					cnt++; 
				} 
			} 
		}
	}
} 

//矩阵的快速转置
void FastTransposeMatrix (TSMatrix T, TSMatrix &M){
	M.rows = T.cols;
	M.cols = T.rows;
	M.numbers = T.numbers;
	int num[100]; //num[n]表示矩阵T中第n列中非零元的个数
	int cpot[100]; //cpot[n]表示矩阵T中第n列中第一个非零元素在M中的位置 
	if (M.numbers != 0) {
		int col, t, p, q;
		for (col = 1; col <= T.cols; ++col){ //初始化T中各列元素个数为0 
			num[col] = 0;
		}
		for (t = 1; t <= T.numbers; ++t){
			++num[T.data[t].j];
		} 
		cpot[1] = 1;
		//求第col列中第一个非零元在b.dataa中的序号
		for (col = 2; col < T.rows; ++col){
			cpot[col] = cpot[col-1] + num[col-1];
		} 
		for (p = 1; p <= T.numbers; ++p){
			col = T.data[p].j;
			q = cpot[col];
			M.data[q].i = T.data[p].j;
			M.data[q].j = T.data[p].i;
			M.data[q].e = T.data[p].e;
			++cpot[col];
		}
	} 
} 

实验用例测试:

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Spraing※boy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值