数据结构 - 数组、矩阵、广义表存储

数组的定义

  1. 数组的定义

    数组是下标index 和值value 组成的序对的集合。

    在数组中,每个有定义的下标都与一个值对应,这个值称做数组元素。

    每个序对形如: (index,value)

数组的顺序表示和实现

由于计算机的内存结构是一维的,因此用一维内存来表示多维数组,就必须按某种次序将数组元素排成一列序列,然后将这个线性序列存放在存储器中。

一般都是采用顺序存储的方法来表示数组

  1. 一维数组的顺序表示

    设第一个数组元素a[0]的存储地址是loc(a[0]),若已知每个数组元素占k个存储单元,则下标为i的数组元素a[i]的存储地址loc(a[i])为

    loc(a[i])=loc(a[0])+i*k

    i=0,1,2,…,n-1。

  2. 二维数组的顺序表示

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

    大多数语言如PASCAL、BASIC、C、C++等都是按行优先顺序存储的,FORTRAN是按列优先顺序存储的。

矩阵的压缩存储

矩阵的存储——二维数组

考虑:若矩阵阶数很高,且有许多值相同的元素或零元素,怎么提高存储效率?

特殊矩阵——值相同的元素或者零元素在矩阵中的分布有一定规律

稀疏矩阵——矩阵中有大量零元素,非零元素比较少。

压缩存储:为多个相同的非零元素只分配一个存储空间;对零元素不分配空间。

对称矩阵的压缩存储

若i≧j,则aij 在下三角矩阵中。 aij 之前的i-1行(从第1行到第i-1行)一共有1+2+…+i-1=i(i-1)/2个元素,在第i行上, aij 之前恰有j-1个元素(即ai0,ai1,ai2,…,aij-1),因此有:
               k=i*(i-1)/2+j-1                 当 i≧j
 若i<j,则aij 是在上三角矩阵中。因为aij=aji,所以只要交换上述对应关系式中的i和j即可得到:
              k=j*(j-1)/2+i-1                  当 i<j
    根据上述的下标对应关系,对于矩阵中的任意元素aij,均可在一维数组sa中唯一确定其位置k;反之,对所有k=0,1, …, n(n+1)/2-1,都能确定sa[k]中的元素在矩阵中的位置(i,j)。

三角矩阵的压缩存储

三角矩阵中的重复元素c可共享一个存储空间,其余的元素正好有n(n+1)/2个,因此,三角矩阵可压缩存储到一维数组sa[n(n+1)/2+1]中,其中c存放在数组的第1个位置(亦可放在最后一个位置)。

上三角矩阵元素aij保存在数组sa中时,下标值k与(i,j)之间的对应关系是?

下三角矩阵元素aij保存在数组sa中时,下标值k与(i,j)之间的对应关系是?

稀疏矩阵的存储

解决方法:在存储非零元素的同时,同时记下它所在的行和列的位置(i, j)。

由于三元组(i, j, aij)唯一确定了矩阵A的一个非零元。因此,稀疏矩阵可由表示非零元的三元组及其行列数唯一确定。

例如,下列三元组表

( (1,2,12), (1,3,9), (3,1,-3), (3,8,4), (4,3,24), (4,6,2), (5,2,18), (6,7,-7), (7,4,-6) ) 和行列信息(7,8,9)便可描述如图5.6所示的稀疏矩阵

注:行列信息(7,8,9)中,7:行;8:列;9:非零元个数

三元组顺序表

以顺序存储结构来表示三元组表,则得到稀疏矩阵的一种压缩存储方法——三元顺序表。

⑴ 三元组结点定义
  #define MAX_SIZE 1000
  typedef int elemtype ;
  typedef struct
{    int   row ;     /*  行下标  */
      int   col ;        /*  列下标  */
elemtype value;      /*  元素值  */
}Triple ;
⑵  三元组顺序表定义
typedef struct
{   int  rn ;         /*   行数   */
int  cn;         /*   列数   */
int  tn ;         /*    非0元素个数   */
Triple   data[MAX_SIZE] ;
}TMatrix ;
TMatrix  a;//定义了一个用三元组顺序表表示的稀疏矩阵

矩阵的转置

设稀疏矩阵A是按行优先顺序压缩存储在三元组表a.data中,若仅仅是简单地交换a.data中i和j的内容,得到三元组表b.data,b.data将是一个按列优先顺序存储的稀疏矩阵B,要得到按行优先顺序存储的b.data,就必须重新排列三元组表b.data中元素的顺序。

由于A的列是B的行,因此,按a.data的列序转置,所得到的转置矩阵B的三元组表b.data必定是按行优先存放的。

转置矩阵的算法

按方法一求转置矩阵的算法如下:
void TransMatrix(TMatrix a , TMatrix * b)
{   int i , j , col ;
b->rn=a.cn ; b->cn=a.rn ; b->tn=a.tn ;
/*    置三元组表b->data的行、列数和非0元素个数 */
if  (b->tn==0)    printf(“ The Matrix A=0\n” );
else{   j=0; //b中三元组 数组下标
for  (col=1; col<=a.cn ; col++)
/*   每次循环扫描 a的第col 列非零元,得到b的第col行非零元  */
      for  (i=0 ;i<a.tn ; i++)  /*   循环次数是非0元素个数   */
                                 if  (a.data[i].col==col)
                                   {    b-> data[j].row=a.data[i].col ;
                                         b-> data[j].col=a.data[i].row ;
                                         b-> data[j].value=a.data[i].value;
                                         j++ ;
                                     }
                    }  }

快速转置算法

快速转置算法如下
   void  FastTransMatrix(TMatrix a, TMatrix b)
{    int p , q , col , k ;
int num[N] , copt[N] ;  //N为矩阵列数
b.rn=a.cn ; b.cn=a.rn ; b.tn=a.tn ;
 /*   置三元组表b.data的行、列数和非0元素个数  */
if  (b.tn==0)    printf(“ The Matrix A=0\n” ) ;
else
{  for (col=1 ; col<=a.cn ; ++col)    num[col]=0 ;
   /*  向量num[ ]初始化为0   */
               for (k=0 ; k<a.tn ; ++k)
      ++num[ a.data[k].col] ;
           /*   求原矩阵中每一列非0元素个数  */
for (cpot[1]=0, col=2 ; col<=a.cn ; ++col)
       cpot [col]=cpot[col-1]+num[col-1] ;
      /*  求第col列中第一个非0元在b.data中的序号 */
for (p=0 ; p<a.tn ; ++p)
    {   col = a.data[p].col ;
         q=cpot[col] ; //矩阵b的第col行的元素所在位置
          b.data[q].row=a.data[p].col ;
          b.data[q].col=a.data[p].row ;
           b.data[q].value=a.data[p].value ;
           ++cpot[col] ;      /*至关重要!!当本列中增加新元素时,位置即变为下一个非零元素的位置  */
     }
}
}

十字链表(链式存储)

    对于稀疏矩阵,当非0元素的个数和位置在操作过程中变化较大时,采用链式存储结构表示比三元组的线性表更方便。
   矩阵中非0元素的结点所含的域有:行、列、值、行指针(指向同一行的下一个非0元)、列指针(指向同一列的下一个非0元)。其次,十字交叉链表还有一个头结点

稀疏矩阵中同一行的非0元素的由right指针域 链接成一个行链表, 由down指针域链接成一个列链表。

每个非0元素既是某个行链表中的一个结点,同时又是某个列链表中的一个结点,所有的非0元素构成一个十字交叉的链表,称为十字链表。

此外,用两个一维数组rhead和chead分别存储行链表的头指针和列链表的头指针。
结点的描述如下:
typedef struct  OLnode
{   int  row , col ;   /*  行号和列号  */
elemtype value ;    /*  元素值  */
struct  OLnode  *down , *right ;
} OLNode, *OLink ;   /*  非0元素结点  */

typedef struct
{   int   rn;        /*  矩阵的行数  */
int   cn;        /*  矩阵的列数  */
int   tn;        /*  非0元素总数  */
OLink  * rhead ;      //行链表头指针向量基址
OLink  * chead ;    //列链表头指针向量基址
} CrossList 

广义表

广义表是线性表的推广和扩充,在人工智能领域中应用十分广泛。

第2章中的线性表定义为n(n≧0 )个元素a1, a2 ,…, an的有穷序列,该序列中的所有元素具有相同的数据类型且只能是原子项(Atom)。所谓原子项可以是一个数或一个结构,在结构上不可再分。若放松对元素的这种限制,容许它们具有其自身结构,就产生了广义表的概念。

广义表(Lists,又称为列表 ):是由n(n ≧0)个元素组成的有穷序列: LS=(a1,a2,…,an) ,其中ai或者是原子项,或者是一个广义表。LS是广义表的名字,n为它的长度。若ai是广义表,则称为LS的子表。

习惯上:原子项用小写字母,子表用大写字母。

若广义表LS非空时:

◆ a1(表中第一个元素)称为表头;

◆ 其余元素组成的子表称为表尾;(a2,a3,…,an)

◆ 广义表中所包含的元素(包括原子和子表)的个数称为表的长 度。

◆ 广义表中括号的最大层数称为表深 (度)

广义表的元素可以是原子项,也可以是子表,子表的元素又可以是子表, …。即广义表是一个多层次的结构。表5-2中的广义表D的图形表示如图5-12所示。

广义表可以被其它广义表所共享,也可以共享其它广义表。广义表共享其它广义表时不必列出子表的值,而是通过表名引用。如:D=(A,B,C)

广义表本身可以是一个递归表。如:E=(a,E)

根据对表头、表尾的定义,任何一个非空广义表的表头可以是原子,也可以是子表, 而表尾必定是广义表。

广义表的存储结构

由于广义表中的数据元素具有不同的结构,通常用链式存储结构表示,每个数据元素用一个结点表示。因此,广义表中就有两类结点:

◆ 一类是表结点,用来表示广义表项,由标志域,表头指针域,表尾指针域组成;

◆ 另一类是原子结点,用来表示原子项,由标志域,原子的值域组成。如图5-13所示。

只要广义表非空,都是由表头和表尾组成。即一个确定的表头和表尾就唯一确定一个广义表。

相应的数据结构定义如下:
typedef struct GLNode
{  int   tag ;     /*  标志域,为1:表结点;为0 :原子结点  */
union
{  Atomtype atom;     /* 原子结点的值域  */
struct
    {  struct GLNode  *hp , *tp ;
     }ptr ;   /*  ptr和atom两成员共用  */
}Gdata ;
} GLNode ;      /* 广义表结点类型  */
时间: 2024-10-14 05:46:26

数据结构 - 数组、矩阵、广义表存储的相关文章

第五章:1.数组和广义表 -- 数组

前言: 2.3.4章讨论的线性结构中的数据元素都是非结构的原子类型,元素的值是不再分解的.本章讨论的两种数据结构---数组和广义表可以看成是线性表在下述含以上的扩展:表中的数据元素本身也是一个数据结构. 其中.数组是一种比较熟知的数据类型,几乎所有程序语言都把数组类型设定为固有类型,前两节节以抽象数据类型的形式讨论数组的定义和实现,使读者加深对数组的理解. 目录: 1.数组的定义 2.数组的顺序表示和实现 3.矩阵的压缩存储 4.广义表的定义 5.广义表的存储结构 6.m元多项式的表示 7.广义

5-5-广义表(头尾链表存储表示)-数组和广义表-第5章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第5章  数组和广义表 - 广义表(头尾链表存储表示) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SequenceString.c    

5-6-广义表(扩展线性链表存储表示)-数组和广义表-第5章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第5章  数组和广义表 - 广义表(扩展线性链表存储表示) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SequenceString.c  

数据结构实践项目——数组和广义表

本文针对 [数据结构基础系列网络课程(5):数组和广义表] 1. 数组的基本概念与存储结构 2. 特殊矩阵的压缩存储 3. 稀疏矩阵的三元组表示 4. 稀疏矩阵的十字链表表示 5. 广义表 6. 广义表的存储结构及基本运算的实现 [项目1 - 猴子选大王(数组版)] 一群猴子,编号是1,2,3 -m,这群猴子(m个)按照1-m的顺序围坐一圈.从第1只开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,最后一只出圈的猴子为大王.输入m和n,输出猴子离开圈子的顺序,从中也可以看出最后为大王是几号

数据结构与算法系列研究四——数组和广义表

稀疏矩阵的十字链表实现和转置 一.数组和广义表的定义 数组的定义1:一个 N 维数组是受 N 组线性关系约束的线性表.           二维数组的逻辑结构可形式地描述为:           2_ARRAY(D,R)              其中 D={aij} | i=0,1,...,b1-1; j=0,1,...,b2-1;aij∈D0}              R={Row,Col}              Row={<aij,ai,j+1>|0<=i<=b1-1;

数组和广义表-第5章-《数据结构题集》答案解析-严蔚敏吴伟民版

习题集解析部分 第5章 数组和广义表 ——<数据结构题集>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑       本习题文档的存放目录:数据结构\▼配套习题解析\▼05 数组和广义表       文档中源码的存放目录:数据结构\▼配

5-4-十字链表(稀疏矩阵)-数组和广义表-第5章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第5章  数组和广义表 - 十字链表(稀疏矩阵) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c        相关测试数据下载

5-2-三元组顺序表(稀疏矩阵)-数组和广义表-第5章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第5章  数组和广义表 - 三元组顺序表(稀疏矩阵) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c        相关测试数据下

数据结构22:数组和广义表

本章主要介绍了数组和广义表的相关知识.数组章节,重点理解矩阵压缩存储的方式,在此基础上,学习矩阵的转置.乘法.和加法运算的实现:学习广义表时重点理解用递归的思想求广义表的深度和复制广义表. 本章内容: 1. 数据结构之多维数组 2. 矩阵压缩存储(十字链表.三元组顺序表.行逻辑 3. 矩阵转置算法及代码实现(三元组顺序表) 4. 矩阵乘法(行逻辑链接的顺序表)及代码实现 5. 矩阵加法(基于十字链表)及C语言代码实现 6. 广义表及M元多项式的C语言代码实现 7. 广义表的长度和深度 8. 广义

数据结构期末复习第五章数组和广义表

数据结构期末复习第五章 数组和广义表 二维数组A[m][n]按行优先 寻址计算方法,每个数组元素占据d 个地址单元.     设数组的基址为LOC(a11) :LOC(aij)=LOC(a11)+((i-1)*n+j-1)*d     设数组的基址为LOC(a00) :LOC(aij)=LOC(a00)+( i*n+j )*d    二维数组A[m][n]按列优先 寻址计算方法,每个数组元素占据d 个地址单元.     设数组的基址为LOC(a11) :LOC(aij)=LOC(a11)+((j