数据结构A(4章)

文章详细介绍了数组的定义、顺序表达,包括一维和二维数组的行优先和列优先存储方式。接着,提出了数组的抽象数据类型(ADTArray),展示了如何使用C语言实现三维数组的操作。此外,文章讨论了对称矩阵的存储优化和稀疏矩阵的概念,提出稀疏矩阵的三元组表示和转置算法,包括简单的转置和基于三元组的快速转置方法。
摘要由CSDN通过智能技术生成

第四章、数组与字符串

一、数组

1.数组定义

  • 下标index 和值value;每个偶对形如: (index,value)

示例:

在这里插入图片描述

2.数组顺序表达

2.1一维数组:

设第一个数组元素a[0]的地址是loc(a[0]),若已知每个元素占k个存储单元,则a[i]的地址loc(a[i])为
loc(a[i])=loc(a[0])+i*k (i=0,1,2,…,n-1)。

2.2二维数组:

二维数组a[m][n]映射到一维的存储空间时有两种顺序:
行优先和列优先。

2.2.1行优先顺序地址计算:

若已知每个元素占k个存储单元,第一个数组元素a[0][0]的地址是loc(a[0][0]),则数组元素a[i][j]的地址loc(a[i][j])为
loc(a[i][j])=loc(a[0][0])+(i*n+j)*k (0i<m;0j<n)

在这里插入图片描述

2.2.2列优先顺序存储:

loc(a[i][j])=loc(a[0][0])+(j*m+i)*k (0i<m;0j<n)

在这里插入图片描述

总结:

  • 行优先:loc(a[i][j])=loc(a[0][0])+(i×n+j)×k

  • 列优先:loc(a[i][j])=loc(a[0][0])+(j×m+i)×k

3.数组的抽象数据类型:

ADT Array{
数据:
下标i = < i1, i2, …, in >和元素v的偶对<i, v>集合。其中n是数组维度,i1, i2, …, in 表示元素在数组各个维度的下标值;数组在各个维度的长度分别是m1, m2, …, mn;数据元素类型为ElemType。
运算:
CreateArray (A, m1, m2, …, mn):创建运算,申请n维数组A所需存储空间并分配给数组A;成功分配则返回OK;否则返回ERROR
DestroyArray (A):清除运算,A存在则撤销数组返回OK,否则返回ERROR;
RetrieveArray (A, i1, i2, …, in, x):数组元素查询运算,在参数x中返回下标为i1, i2, …, in的数组元素;若数组不存在或某下标越界,则返回ERROR
StoreArrayItem (A, i1, i2, …, in, x):数组元素赋值运算,将下标为i1, i2, …, in的数组元素值设置为x;
OutputArray (A):数组输出运算,将数组中所有元素依次输出;
CopyArray (A, B): 数组拷贝运算,将数组A中元素依次拷贝到数组B中;
……
}

3.1数组操作代码演示:
//实现一个三维整型数组类型TDArray及其运算。
typedef struct triplearray    
{
    int m1;
    int m2;
    int m3;
    int *array;
}TripleArray;

Status CreateArray (TripleArray *triArray, int m1, int m2, int m3)
{
     triArray ->m1 = m1;
     triArray ->m2 = m2;
     triArray ->m3 = m3;
     triArray ->array = (int *)malloc(m1*m2*m3*sizeof(int));
    if(! triArray ->array) return ERROR;
    return OK;
}

Status DestroyArray (TripleArray *triArray)
{
    if(!triArray) return ERROR;
    if(triArray ->array)
        free(triArray ->array);
    return OK;
}

Status RetrieveArray(TripleArray triArray, int i1, int i2, int i3, int* x)
{
    if (!triArray.array) return NotPresent;
    if (i1 < 0 || i2 < 0 || i3 < 0 || i1 >= triArray.m1
          || i2 >= triArray.m2 || i3 >= triArray.m3)
         return IllegalIndex;
    *x = *(triArray.array + i1 * triArray.m2 * triArray.m3 + i2 * triArray.m3 + i3);
     return OK;
} 

Status StoreArrayItem(TripleArray* triArray, int i1, int i2, int i3, int x)
{
    if (!triArray->array) return NotPresent;
    if (i1 < 0 || i2 < 0 || i3 < 0 || i1 >= triArray->m1
             || i2 >= triArray->m2 || i3 >= triArray->m3)
            return IllegalIndex;
    *(triArray->array + i1 * triArray->m2 * triArray->m3 + i2 * triArray->m3 + i3) = x;
     return OK;
}     
void OutputArray(TripleArray triArray)
{
int i1, i2, i3;
for (i1=0;i1<triArray.m1 ;i1++)
for (i2=0;i2<triArray.m2;i2++)
for (i3 = 0; i3 < triArray.m3; i3++)
{
int value;
RetrieveArray(triArray, i1, i2, i3, &value);
printf("array [%d][%d][%d]=%d\n", i1, i2, i3, value);
}
}

int main()
{
    int i1, i2, i3;
    TripleArray TripleArrayA, TripleArrayB;
    CreateArray(&TripleArrayA, 2, 2, 2);
    CreateArray(&TripleArrayB, 2, 2, 2);
    for (i1 = 0; i1 < TripleArrayA.m1; i1++)
       for (i2 = 0; i2 < TripleArrayA.m2; i2++)
           for (i3 = 0; i3 < TripleArrayA.m3; i3++)
            {
                 StoreArrayItem(&TripleArrayA, i1, i2, i3, 10);
                 StoreArrayItem(&TripleArrayB, i1, i2, i3, 5);
            }
     OutputArray(TripleArrayA);
     OutputArray(TripleArrayB);
     CopyArray(&TripleArrayA,&TripleArrayB);
     OutputArray(TripleArrayA);
     OutputArray(TripleArrayB);
    return 0;
}


4.矩阵

4.1对称矩阵 (行列优先及上下三角问题)

在这里插入图片描述

n 2 n^2 n2个元素的对称矩阵,只需要n(n+1)/2个元素的存储空间。

4.1.2对称矩阵的行优先存储
  • 若用一维数组B[num]以行优先顺序存储下三角(包括对角线)元素,则矩阵元素aij的下标(i,j)和该元素在数组B中的存储位置k之间有如下关系:

在这里插入图片描述

  • 行优先顺序存储上三角关系如下:

在这里插入图片描述

4.2上(下)三角矩阵

在这里插入图片描述

4.3稀疏矩阵
  • 定义:大多数元素为零的矩阵称为稀疏矩阵。
    矩阵中非零元素数量占元素总数的比例称为矩阵的稠密度
    当矩阵的稠密度很小,即包含大量零元素的矩阵称为稀疏矩阵 (sparse matrix)
    通常认为稠密度小于5%的矩阵即可视为稀疏矩阵
    稀疏矩阵中零元素的位置分布没有规律。
    稀疏矩阵常出现于大规模集成电路设计、图像处理等应用领域。
    由于稀疏矩阵中只有少量非零元素,为了节省存储空间,对稀疏矩阵可以只存储非零元素。

  • 稀疏矩阵ADT

ADT SparseMatrix{
数据: 大多数元素为零的矩阵。
运算:  
CreateMatrix(M, m,n):构造运算,构造一个m×n的空稀疏矩阵。 
Clear(M):清除运算,清除稀疏矩阵中的所有非零元素。
Transpose(A):转置运算,返回稀疏矩阵A的转置矩阵。
Madd(A, B):加法运算,返回稀疏矩阵A和B的和。
MMulti(A, B):乘法运算,返回稀疏矩阵A和B的积。
StoreSparseMatrixItem (M, i, j, x):稀疏矩阵元素赋值运算,设置稀疏矩阵中下标为i, j的元素值为x。
RetrieveSparseMatrix (M, i, j, x):稀疏矩阵元素查找运算,在参数*x中返回零值。
OutputSparseMatrix (A):稀疏矩阵输出运算,将矩阵所有非零元素依次输出。
}
4.3.1稀疏矩阵顺序存储

(1)三元组表达式:

稀疏矩阵Am×n中的每一个非零元素 aij 的行号i、列号j和值v表示为一个三元组,即:( i, j, v)

(2)行(列)存储:

在这里插入图片描述

(3)三元组的存储结构:

typedef struct term{
    int  row;                  //非零元在稀疏矩阵中的行下标row
    int  col;              //非零元在稀疏矩阵中的列下标col
    ElemType  value;   //非零元的值
}Term;

typedef struct sparsematrix{
    int  m;      //矩阵行数
       int  n;       //矩阵列数
       int  t;      //非零元个数
    Term *table;    //存储非零元的三元组表
}SparseMatrix;
4.4矩阵转置方法
  • 前件知识:

在这里插入图片描述

4.4.1稀疏矩阵的简单转置算法
  • 采用二维数组A存储一个普通 m×n 矩阵,假设将矩阵转置结果存储到 n×m 矩阵B中:
for(int i=0; i<m; i++)
    for(int j=0; j<n; j++)
        B[j][i] = A[i][j];
//时间复杂度为O(m*n)
4.4.2三元组实现矩阵转换
  • 如果稀疏矩阵Am×n用行三元组M表示,
    转置矩阵保存在一维数组T中,转置之后的T应仍为行三元组。

在这里插入图片描述

(1)方法一:将数组 M 中的元素的行、列号交换后保存到 T 数组中;然后按 T 中的行号排序。

在这里插入图片描述

(2)方法二:对数组 M(矩阵Am  n的三元组) 扫描 n 遍,每遍扫描t次。第 i 遍扫描,找到M中列号为i的元素(即A中第i列中的非0元素),将该元素转置后依次放入T中。

k=0;
for(i=0; i<n; i++)
     for(j=0; j<t; j++)
           if(M[j].col == i)  { 
                  T[k].col = M[j].row;
                  T[k].row = M[j].col;
                  T[k++].value = M[j].value;
           }
//时间复杂度为O(n*t)
t是T的长度。

在这里插入图片描述

(3)方法三:快速转置

#include <stdio.h>
#include <stdlib.h>
typedef struct {
	int row, col;
	int value;
} Triple;

void transpose(int m, int n, int len, Triple* a, Triple* b) {
	int* num, * cpot;
	num = (int*)calloc(n + 1, sizeof(int));
	cpot = (int*)calloc(n + 1, sizeof(int));
	for (int i = 0; i < len; i++) {
		num[a[i].col]++;
	}
	cpot[1] = 0;
	for (int i = 2; i <= n; i++) {
		cpot[i] = cpot[i - 1] + num[i - 1];
	}
	for (int i = 0; i < len; i++) {
		int col = a[i].col;
		int pos = cpot[col];
		b[pos].row = a[i].col;
		b[pos].col = a[i].row;
		b[pos].value = a[i].value;
		cpot[col]++;
	}
	free(num);
	free(cpot);
}

int main() {
	Triple a[] = { {1, 2, 3},
	{1, 3, 4},
	{2, 1, 5},
	{3, 2, 6} };
	int m = 3, n = 3, len = sizeof(a) / sizeof(Triple);
	Triple* b = (Triple*)malloc(len * sizeof(Triple));
	transpose(m, n, len, a, b);
	
	printf("原始稀疏矩阵:\n");
	for (int i = 0; i < len; i++) {
		printf("(%d,%d,%d)\n", a[i].row, a[i].col, a[i].value);
	}
	printf("转置稀疏矩阵:\n");
	for (int i = 0; i < len; i++) {
		printf("(%d,%d,%d)\n", b[i].row, b[i].col, b[i].value);
	}
	free(b);
b[i].row, b[i].col, b[i].value);
	}
	free(b);
}

在这里插入图片描述

逻辑解释:col[i] 记录列数;num[i] 记录非零元素个数;K[i] 表示首个非零元素在三元组中的位置。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值