三元组顺序表存储稀疏矩阵并实现两种转置算法

稀疏矩阵

    当矩阵中只有极少的非零元素,而且分布也不规律,如果非零元素个数只占矩阵元素总数的25%~30%或低于这个百分数时,这样的矩阵称为稀疏矩阵。

三元组顺序表

    对于稀疏矩阵中的非零元素来说,行号,列号以及元素值三项值可以唯一地确定该元素。元组顺序表中的三元恰好反映了这三项值,即(row,col,value),row代表行号,col代表列号,value代表元素值。然而,这样仍不能唯一地确定一个稀疏矩阵。对于三元组表来说,还必须给出矩阵的总行数,总列数以及非零元素的个数,这样才能唯一地确定一个稀疏矩阵。

顺序存储结构

typedef struct 
{
	int row, col;
	DataType value;
}Triple;

typedef struct
{
	Triple data[MAXSIZE + 1]; // 一维数组
	int rows, cols, nums;  //矩阵的行数,列数和非零元素个数
}TSMatrix;

转置运算

(1)按列序递增进行转置

算法思想

    ① 扫描原三元组,并按照先列序后行序的原则进行。即第一遍从原三元组的第一行开始向下搜索列号为1的元素,只要找到则顺序存入转置后的三元组表;

    ② 第2遍仍然从原三元组的第一列开始向下搜索列号为2的元素,只要找到则顺序存入转置后的三元组表;

    ......

    ③ 第n遍(n代表原三元组总共有多少列)将列号为n的元素,依次填入转置后的三元组表。

主要介绍原始算法和改进后的算法

// 转置运算(扫描三元组,按照先列序后行序的原则进行)
void TransposeTSMatrix1 (TSMatrix *A, TSMatrix *B)
{
	int i, j, k;
	B->rows = A->cols;
	B->cols = A->rows;
	B->nums = A->nums;
	
	if (B->nums >0)
	{	
		k = 1;
		for (i = 1; i <= A->cols; i++) // A的列数就是B的行数,对应要循环找几次B的行号
		{
			for (j = 1; j <= A->nums; j++) 
			{
				if (A->data[j].col == k) // 每次将A中列号和K相等的赋值到A的行号去
				{
					B->data[k].row = A->data[j].col;
					B->data[k].col = A->data[j].row;
					B->data[k].value = A->data[j].value;
					k++;
				}
			}
		}
	}
}

// 改进后的按列序递增进行矩阵转置
// 就是利用非零元素的个数加以控制,让外重循环提前结束
void TransposeTSMatrix2 (TSMatrix *A, TSMatrix *B)
{
	int i, j, k;
	B->rows = A->cols;
	B->cols = A->rows;
	B->nums = A->nums;
	
	if (B->nums >0)
	{	
		k = 1;
		for (i = 1; i <= A->cols; i++) // A的列数就是B的行数,对应要循环找几次B的行号
		{
			for (j = 1; j <= A->nums; j++) 
			{
				if (A->data[j].col == k) // 每次将A中列号和K相等的赋值到A的行号去
				{
					B->data[k].row = A->data[j].col;
					B->data[k].col = A->data[j].row;
					B->data[k].value = A->data[j].value;
					k++;
				}
				if (k > A->nums)
					break;
			}
		}
	}
}

(2)一次定位快速转置

算法思想    

    该算法是对被转置矩阵的三元组表只扫描一次,使得所有的非零元素一次性存放到转置后的三元组表中。

    主要就在于num[col](存放第col列元素个数)和position[col](转置后第col行的开始位置)

    ① 扫描原矩阵A的三元组表,统计出其中每一列的非零元素的个数,存放到数组num[col]中(num[col]存放原矩阵A中第col列的非零元素个数)
    ② 计算转置矩阵的每一行在其三元组表中的开始位置,并存放到position[col]中(position[col]存放转置矩阵中第col行的开始位置)

    ③ 再次扫描原矩阵A的三元组表,根据非零元素的列号col,确定它转置后的行号,查position表,按查到的位置直接将该项存入转置三元组中,并修改position[col],将其指向该行下一个元素的存储位置(position[col]++)。

void Fast_TransposeTSMatrix (TSMatrix *A, TSMatrix *B)
{
	int col, t, p;
	int num[MAXSIZE], position[MAXSIZE];
	position[1] = 1;
	if (B->nums)
	{
		for (col = 1; col <= A->cols; col++)
			num[col] = 0;
		for (t = 1; t <= A->nums; t++)
			num[A->data[t].col] ++;
		
		for (col = 2; col <= A->cols; col++)
			position[col] = position[col-1] + num[col-1];

		for (p = 1; p <= A->nums; p++)
		{
			col = A->data[p].col;
			B->data[position[p]].row = A->data[p].col;
			B->data[position[p]].col = A->data[p].row;
			B->data[position[p]].value = A->data[p].value;
			position[col]++;
		}
	}
	
}

总结

    按列序递增进行转置就是通过原三元组A中的col数,依次按照1-col的顺序存入到新三元组B中。而一次定位快速转置算法则是事先通过三元组A的列(对应于三元组B的行)找到每个col号中元素的数目和每个col号的起始位置,从而在三元组B中直接定位位置存入。

    
  • 29
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值