数据结构之数组和广义表

读自《数据结构(C语言版)》严蔚敏 吴伟民 清华大学出版社
当线性结构中的数据元素是原子类型时,即元素的值不再分解的(数据元素为int,char,…)
当数据元素是一个数据结构时,为非原子类型的。
C语言中,二维数组以行序为主序存储。
数组的顺序存储表示

#include <stdarg.h> //标准头文件,提供宏va_start/va_arg和va_end,
            //用于存取变长参数表
#define MAX_ARRAY_DIM 8
typedef struct{
    type *base;  //数组元素基址,由InitArray分配
    int dim;  //数组维数
    int *bounds;  //数组维界基址,由InitArray分配
    int *constants;  //数组映像函数常量基址,由InitArray分配
}

矩阵的压缩存储,数值分析中经常出现一些阶数很高的矩阵,同时矩阵中有许多值相同的元素或者是零元素。有时为了节省存储空间,可以对这类矩阵进行压缩存储。所谓压缩存储是指,为多个值相同的元只分配一个存储空间;对零元不分配空间。
若值相同的元素或者零元素在矩阵中分布有一定规律,则我们称此类矩阵为特殊矩阵,反之,为稀疏矩阵

特殊矩阵
aij = aji 1<=i,j<=n 称为n阶对称矩阵。对于对称矩阵,可将n平方压缩存储到n(n+1)/2个元的空间中。
假设一维数组sa[n(n+1)/2]作为n阶对称矩阵A的存储结构,则sa[k]和矩阵元aij之间存在着一一对应的关系:
k = i(i-1)/2 + j - 1 当i >= j (下三角)
k = j(j-1)/2 + i - 1 当i < j (上三角)

三角矩阵,下(上)三角矩阵是指矩阵的上(下)三角(不包括对角线)中的元均为常数c或零的n阶矩阵。除了和对称矩阵一样,再加上一个存储常数c的存储空间即可

对角矩阵,在这种矩阵中,所有的非零元集中在以主对角线为中心的带状区域中。

m*n的矩阵,a = t/(m*n),t 为不为零的元素个数,a为稀疏因子,a<=0.05时称为稀疏矩阵。
稀疏矩阵可由表示非零元的三元组及其行列数唯一确定
稀疏矩阵的三元组顺序表存储表示

#define MAXSIZE 12500
typedef struct{
    int i,j;  //该非零元的行下标和列下标
    type e;
}Triple;

typedef struct{
    Triple data[MAXSIZE+1];  //非零元三元组表,data[0]未用
    int mu,nu,tu;  //矩阵的行数,列数,非零元个数
}TSMatrix;

m*n矩阵M转置矩阵T是一个n*m矩阵
转置操作:
1.将矩阵的行列值相互交换
2.将每个三元组中的i和j相互调换
3.重排三元组之间的次序便可实现矩阵的转置

两种处置转置的方法

Status TransposeSMatrix(TSMatrix M, TSMatrix &T){
    T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;
    if(T.tu){
        q = 1;
        for(col = 1; col <= M.nu; ++col)
            for(p = 1; p <= M.tu; ++p)
                if(M.data[p].j == col){
                    T.data[q].i = M.data[p].j;
                    T.data[q].j = M.data[p].i;
                    T.data[q].e = M.data[[p].e;
                    ++q;
                }
    }
    return OK;
}

第二种就是先求得M的每一列中非零元的个数,进而求得每一列的第一个非零元在b.data中应有的位置,需要附设num和cpot两个向量。num[col]表示矩阵M中第col列中非零元的个数,cpot[col]指示M中第col列的第一个非零元在b.data中恰当位置
cpot[1] = 1;
cpot[col] = cpot[col - 1]+num[col - 1] 2<= col <= a.nu

行逻辑链接的顺序表
三元组顺序表又称有序的双下标法,它的特点是,非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算。然而,如需要按行号存取某一行的非零元,则需要从头开始进行查找。
为了便于随机存取任意一行的非零元,则需知道每一行的第一个非零元在三元组表中的位置。我们借助指示行信息的辅助数组cpot

typedef struct{
    Triple data[MAXSIZE + 1];  //非零元三元组
    int rpos[MAXRC + 1];  //各行第一个非零元的位置表
    int mu, nu, tu;   //矩阵的行数,列数和非零元个数
}RLSMatrix;

十字链表

广义表
广义表是线性表的推广,LS = (a1, a2, a3,…,an)
广义表的定义中,ai可以是单个元素,也可以是广义表,分别称为广义表LS的原子子表
习惯上,用大写字母表示广义表的名称,用小写字母表示原子。当广义表LS非空时,称第一个元素a1为LS的表头(Head),称其余元素组成的表(a2, a3, … , an)是LS的表尾(Tail)
列表的元素可以是子表,而子表的元素还可以是子表
列表可为其他列表所共享
列表可是一个递归的表,即列表也可以是其本身的一个子表
任何一个非空列表其表头可能是原子,也可能是列表,而其表尾必定为列表
广义表采用链式存储结构,需要用两种结构的结点:一种是表结点,用以表示列表;一种是原子结点,用以表示原子。
广义表的头尾链表存储表示

typedef enum{ATOM, LIST}ElemTag; //ATOM==0:原子,LIST == 1:子表
typedef struct GLNode{
    ElemTag tag; //公共部分,用于区分原子结点还是表结点
    union{  //原子结点和表结点的联合部分
        AtomType atom; //atom是原子结点的值域,AotmType由用户定义
        struct{struct GLNode *hp, *tp;}ptr;//ptr是表结点的指针域,ptr.hp和ptr.tp分别指向表头和表尾
    };
}*GList;    //广义表类型

最高层的表结点个数即为列表的长度。
我比较习惯用下面这种结构
//广义表的扩展线性链表存储表示

typedef enum{ATOM, LIST}ElemTag; //ATOM==0:原子,LIST == 1:子表
typedef struct GLNode{
    ElemTag tag; //公共部分,用于区分原子结点还是表结点
    union{  //原子结点和表结点的联合部分
        AtomType atom; //atom是原子结点的值域,AotmType由用户定义
        struct GLNode *hp;//表结点的表头指针
    };
    struct GLNode *tp;   //相当于链表的next,指向下一个元素结点
}*GList;    //广义表类型

广义表的深度为广义表中括弧的重数,是广义表的一种量度。空表深度为1,原子深度为0

int GListDepth(GList L){
    if(!L)return 1;
    if(L->tag == ATOM)return 0;
    for(max = 0, pp = L; pp; pp = pp->ptr.tp){
        dep = GListDepth(pp->ptr.hp);
        if(dep > max) max = dep;
    }
    return max + 1;
}

复制广义表
一对确定的表头和表尾可唯一确定一个广义表,由此,复制一个广义表只要分别复制其表头和表尾,然后合成。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值