数据结构之数组和广义表
2016-03-24 09:58
531 查看
读自《数据结构(C语言版)》严蔚敏 吴伟民 清华大学出版社
当线性结构中的数据元素是原子类型时,即元素的值不再分解的(数据元素为int,char,…)
当数据元素是一个数据结构时,为非原子类型的。
C语言中,二维数组以行序为主序存储。
数组的顺序存储表示
矩阵的压缩存储,数值分析中经常出现一些阶数很高的矩阵,同时矩阵中有许多值相同的元素或者是零元素。有时为了节省存储空间,可以对这类矩阵进行压缩存储。所谓压缩存储是指,为多个值相同的元只分配一个存储空间;对零元不分配空间。
若值相同的元素或者零元素在矩阵中分布有一定规律,则我们称此类矩阵为特殊矩阵,反之,为稀疏矩阵
特殊矩阵
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时称为稀疏矩阵。
稀疏矩阵可由表示非零元的三元组及其行列数唯一确定
稀疏矩阵的三元组顺序表存储表示
m*n矩阵M转置矩阵T是一个n*m矩阵
转置操作:
1.将矩阵的行列值相互交换
2.将每个三元组中的i和j相互调换
3.重排三元组之间的次序便可实现矩阵的转置
两种处置转置的方法
第二种就是先求得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
十字链表
广义表
广义表是线性表的推广,LS = (a1, a2, a3,…,an)
广义表的定义中,ai可以是单个元素,也可以是广义表,分别称为广义表LS的原子和子表
习惯上,用大写字母表示广义表的名称,用小写字母表示原子。当广义表LS非空时,称第一个元素a1为LS的表头(Head),称其余元素组成的表(a2, a3, … , an)是LS的表尾(Tail)
列表的元素可以是子表,而子表的元素还可以是子表
列表可为其他列表所共享
列表可是一个递归的表,即列表也可以是其本身的一个子表
任何一个非空列表其表头可能是原子,也可能是列表,而其表尾必定为列表
广义表采用链式存储结构,需要用两种结构的结点:一种是表结点,用以表示列表;一种是原子结点,用以表示原子。
广义表的头尾链表存储表示
最高层的表结点个数即为列表的长度。
我比较习惯用下面这种结构
//广义表的扩展线性链表存储表示
广义表的深度为广义表中括弧的重数,是广义表的一种量度。空表深度为1,原子深度为0
复制广义表
一对确定的表头和表尾可唯一确定一个广义表,由此,复制一个广义表只要分别复制其表头和表尾,然后合成。
当线性结构中的数据元素是原子类型时,即元素的值不再分解的(数据元素为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; }
复制广义表
一对确定的表头和表尾可唯一确定一个广义表,由此,复制一个广义表只要分别复制其表头和表尾,然后合成。
相关文章推荐
- 数据结构之栈和队列
- 数据结构之线性表
- 排序算法系列:插入排序算法
- 笔试总结——数据结构篇【持续更新】
- 数据结构(一)二叉搜索树-递归实现
- C语言 数据结构与算法 单向链表
- Redis内部实现(数据结构和对象)
- 【数据结构与算法】十二 字符串搜索
- 【数据结构 ?】前端笔试题总结
- 数据结构(19)栈典型问题之C++实现表达式求值
- python 下的数据结构与算法---3:python内建数据结构的方法及其时间复杂度
- 一道数据结构题
- 《大话数据结构》 读书心得
- 数据结构——排序(二)
- 数据结构上机实验(二)
- 数据结构学习网站
- 数据结构面试
- 《数据结构》 循环链表和双向链表常用操作代码集合
- bzoj3223 && Tyvj 1729 文艺平衡树
- MySQL索引背后的数据结构及算法原理