第十二章 数据结构 数组和广义表 + 矩阵的存储 + 稀疏矩阵 + 三元组转置的代码实现

数组

数组的定义,特点及顺序存储

线性表的推广- 数组

数组是我们熟悉的数据结构,可以把数组看作是线性表的推广。
数组的特点是结构中的元素本身可以是具有某种结构的数据, 但属于同一数据类型。
以一维数组为基础, 可以这样观察。
将二维数组看成数据元素是一维数组的一维数组。
将三维数组看成元素是二维数组的一维数组。

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

n维数组中, 每个数据元素受n个关系的约束。
一般来说, 在数组上不能做插入, 删除数据元素的操作。
通常在各种高级语言中数组一旦被定义, 每一维的大小及上下界都不能改变。
取值操作: 给定一组下标, 读其对应的数据元素。
赋值操作: 给定一组下标, 存储或修改与其相对应的数据元素。

由于对数组一般不做插入、删除操作; -旦建立了数组,数据元素个数和元素之间的关系就不再发生变动。

因此, 采用顺序存储结构标表示数组。

是以行为主序(即先行后列)的顺序存放,行存储完了接着存储下一行。
是以列为主序(即先列后行)的顺序存放,列存储完了接着存储下一列。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述获取地址:Loc(aij) = Loc(a1,1) + ((i - 1) * n + j - 1) * L;

特殊矩阵-压缩存储

在这里插入图片描述

对称矩阵的压缩存储方式

在这里插入图片描述

用于缩小存储单元
aij=ajiaij = aji
只需存储n(n+1)/2n * (n + 1) / 2个存储单元.

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

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

带状矩阵

在这里插入图片描述

所需存储空间 3 *n - 2;

在这里插入图片描述

存储位置计算

在这里插入图片描述
LOC(ai,j ) = LOC(a1,1) + ((i - 1) * n + j - 1) * L;
LOC(ai, j) = LOC(a0,0) + (i *n + j ) * L;

例题

在这里插入图片描述

稀疏矩阵

稀疏矩阵中零元很多。
设m x n 矩阵中有t个非零元素且m * nt << m x n,
d = t / (m x n) d就被称为稀疏因子, d <= 0.05时为稀疏矩阵。
在这里插入图片描述

采用顺序存储结构存储非零元的三元组, 称为三元组表, 其中非零元按以行为主序存储。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
显然, 要唯一的表示一个稀疏矩阵, 可在存储三元组表的同时存储该矩阵的行, 列, 为了方便运算, 矩阵的非零元素个个数也同时存储。

➊三 元组表存储的稀疏矩阵,在进行矩阵加法、减法和乘法等操作时,有时矩阵中的非零元素的位置和个数会发生很大的变化。

➊如A=A+ B,将矩阵B加到矩阵A.上,此时若还用三元组表表示法,势必会为了保持三元组表“以行序为主序”而大量移动元素。为此引入了链式存储稀疏矩阵。

➊矩阵中,每一个矩阵元素aij,受两个线性关系的约束,行关系、列关系;每一个关系都是线性的,我们可以用线性链表来存储行关系、列关系;

➊这样,aij就处于第i行的单链表中,也处于第j列的单链表中,就像处十字路口一-样,所以我们将这种存储结构称之为“十字链表”。

在这里插入图片描述

十字链表存储方式

在这里插入图片描述

三元组矩阵的快速转置

三元组矩阵以顺序表模式对稀疏矩阵中的非零元素进行存储, 每个元素记录了其所在的行号,列号以及元素值, 并且非零元素在三元组表中以行号为顺序进行排列。
在这里插入图片描述
在这里插入图片描述
常规算法dest[col][row]=source[row][col]dest[col][row] = source[row][col]
O(mn)O(m * n)

快速转置 - 基本策略

令矩阵M第j列有k个非零元素。 M的第j列构成了转置矩阵T的第j行。

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

算法思想整理

转置矩阵的思想就是实现了元素的行列互换,但我们要保证在转置之后, 三元组依旧按照行顺序存储。

取出原来的三元表中的列元素, 依次对应于转置三元表中的元素,三元表中元素的行则等于它的上一个列元素 的位置+ 上一个列元素中包含的元素。

总结

三元组的优点:实现了稀疏矩阵的高效存储。

三元组的缺点:无法直接随机存取数据元素, 对矩阵运算带来了不便。

本节通过矩阵转置实现了:

压缩存储后算法的特殊性。
优秀算法设计的技巧性和优雅性。

三元组转置_普通转置


#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
typedef int Elemtype;
int a[3][5] = { {1,0,0,0,8},{0,0,5,0,4}, {3,0,0,0,0} };
int aT[5][3];
typedef struct {
	int r;
	int c;
	Elemtype d;
}TupNode;
typedef struct {
	int rows;
	int cols;
	int nums;
	TupNode data[MaxSize];
}TSMatrix;

void GreateMat(TSMatrix &t, TSMatrix &tb) {
	t.rows = 3;
	t.cols = 5;
	t.nums = 0;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 5; j++) {
			if (a[i][j] != 0) {
				t.data[t.nums].r = i;
				t.data[t.nums].c = j;
				t.data[t.nums].d = a[i][j];
				t.nums++;
			}
		}
	}
}
void DispMat(TSMatrix t) {
	if (t.nums <= 0) return;
	else {
		printf("转置前矩阵的三元组顺序表为:\n");
		for (int i = 0; i < t.nums; i++) {
			printf("%d\t%d\t%d\n", t.data[i].r, t.data[i].c, t.data[i].d);
		}
	}
}

void TranTat(TSMatrix t, TSMatrix &tb) {
	tb.rows = t.cols;
	tb.cols = t.rows;
	tb.nums = t.nums;
	int k = 0;
	if (t.nums != 0) {
		for (int i = 0; i < t.cols; i++) {
			for (int j = 0; j < t.nums; j++) {
				if (t.data[j].c == i) {///i是最外层的列  这样做的确可以保证有序性。
					tb.data[k].r = t.data[j].c;
					tb.data[k].c = t.data[j].r;
					tb.data[k].d = t.data[j].d;
					k++;
				}
			}
		}
	}
	printf("转置后矩阵的三元组顺序表为:\n");
	for (int i = 0; i < tb.nums; i++) {
		printf("%d\t%d\t%d\n", tb.data[i].r, tb.data[i].c, tb.data[i].d);
	}
}


int main() {
	TSMatrix t, tb;
	GreateMat(t, tb);
	DispMat(t);
	TranTat(t, tb);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章