数据结构学习笔记——数组和稀疏矩阵

数组和稀疏矩阵

数组的基本概念
    数组是n(n>1)个相同类型数据元素a1,a2,…,an构成的有限序列,且该有限序列存储在一块地址连续的内存单元中。
    由此可见,数组的定义类似于采用顺序存储结构的线性表。

数组具有以下性质:
     (1) 数组中的数据元素数目固定。一旦定义了一个数组,其数据元素数目不再有增减变化。
     (2) 数组中的数据元素具有相同的数据类型。
     (3) 数组中的每个数据元素都和一组惟一的下标值对应。
     (4) 数组是一种随机存储结构。可随机存取数组中的任意数据元素。

    显然,二维数组同样满足数组的定义。一个二维数组可以看作是每个数据元素都是相同类型的一维数组的一维数组。以此类推,任何多维数组都可以看作一个线性表,这时线性表中的每个数据元素也是一个线性表。多维数组是线性表的推广。


      对一个已知以行序为主序的计算机系统中,当二维数组第一个数据元素a1,1的存储地址LOC(a1,1)和每个数据元素所占用的存储单元k确定后,则该二维数组中任一数据元素ai,j的存储地址可由下式确定:
      LOC(ai,j)=LOC(a1,1)+[(i-1)*n+(j-1)]*k
     其中n为列数。
     
     同理可推出在以列序为主序的计算机系统中有:
        LOC(ai,j)=LOC(a1,1)+[(j-1)*m+(i-1)]*k                             
其中m为行数。
 --------------------------------------------------------------------------------
运用数组来实现解约瑟夫问题


特殊矩阵的压缩存储
      特殊矩阵是指非零元素或零元素的分布有一定规律的矩阵,为了节省存储空间,特别是在高阶矩阵的情况下,可以利用特殊矩阵的规律,对它们进行压缩存储,也就是说,使多个相同的非零元素共享同一个存储单元,对零元素不分配存储空间。
     
    对称矩阵,上三角矩阵,下三角矩阵
    对于各种矩阵的存储运算,可以通过数组在内存中的特点,用等差数列请和公式算出

    三对角矩阵的存储:公式b[i][j]=b[k]   K=2i+j(下标从0开始)


稀疏矩阵的三元组表示
    稀疏矩阵的压缩存储方法是只存储非零元素。
    由于稀疏矩阵中非零元素的分布没有任何规律,所以在存储非零元素时还必须同时存储该非零元素所对应的行下标和列下标。这样稀疏矩阵中的每一个非零元素需由一个三元组(i,j,ai,j)惟一确定,稀疏矩阵中的所有非零元素构成三元组线性表。

   若把稀疏矩阵的三元组线性表按顺序存储结构存储,则称为稀疏矩阵的三元组顺序表。则三元组顺序表的数据结构可定义如下:

#define MaxSize  100  /*矩阵中非零元素最多个数*/
typedef 
struct
{    
int r;                     /*行号*/
      
int c;                     /*列号*/
      ElemType d;         
/*元素值*/
} TupNode;                
/*三元组定义*/
typedef 
struct
{    
int rows;                /*行数值*/
      
int cols;                  /*列数值*/
      
int nums;               /*非零元素个数*/
      TupNode data[MaxSize];
} TSMatrix;           
/*三元组顺序表定义*/
   针对于排序的:
     矩阵转置算法及快速矩阵转置算法
   针对于非排序的:
     矩阵转置算法

稀疏矩阵的十字链表表示
      十字链表为稀疏矩阵的每一行设置一个单独链表,同时也为每一列设置一个单独链表。
      这样稀疏矩阵的每一个非零元素就同时包含在两个链表中,即每一个非零元素同时包含在所在行的行链表中和所在列的列链表中。这就大大降低了链表的长度,方便了算法中行方向和列方向的搜索,因而大大降低了算法的时间复杂度。
     
     对于一个m×n的稀疏矩阵,每个非零元素用一个结点表示,结点结构可以设计成如下图(a)所示结构。其中i,j,value分别代表非零元素所在的行号、列号和相应的元素值;down和right分别称为向下指针和向右指针,分别用来链接同列中和同行中的下一个非零元素结点。

|-------------------|
|  i     |  j   | value |
|--------------------
|   down |   right  |
---------------------
         (a)

     十字链表中设置行头结点、列头结点和链表头结点。它们采用和非零元素结点类似的结点结构,具体如下图(b)所示。其中行头结点和列头结点的i,j域值均为0;行头结点的right指针指向该行链表的第一个结点,它的down指针为空;列头结点的down指针指向该列链表的第一个结点,它的right指针为空。行头结点和列头结点必须顺序链接,这样当需要逐行(列)搜索时,才能一行(列)搜索完后顺序搜索下一行(列),行头结点和列头结点均用link指针完成顺序链接。

|-------------------|
|  i     |  j  | next  |
|--------------------
|   down |   right  |
---------------------
         (b)

十字链表结点结构和头结点的数据结构可定义如下:
#define M 3                                /*矩阵行*/
#define N 4                                /*矩阵列*/
#define Max ((M)>(N)?(M):(N))     /*矩阵行列较大者*/
typedef 
struct mtxn
{     
int row;                        /*行号*/
      
int col;                /*列号*/
      
struct mtxn *right,*down;    /*向右和向下的指针*/
      union
      {     
int value;
            
struct mtxn *link;
      } tag;
 }  MatNode            
/*十字链表类型定义*/

--------------------------------------------------------------------------------
注意:每组行列头节点共用一个存储空间,并行列头节点与头节点链成一个循环链表,对行列头节点之间采用顺序链接,动态申请一组个数为矩阵行列较大者的一维数组空间,下标号对应各自的当前行列;对元素而言,它们也在对应的行列方向上,形成各自对应该行列的与行头结点及列头节,形成循环链表。

--------------------------------------------------------------------------------
例:设计一个用于存储双层集合的存储结构,所谓双层集合是指这样的集合,其中每个元素又是一个集合(称为集合元素),该集合元素由普通的元素构成。如,s={{1,3},{1,7,8},{5,6}}.
原文地址:https://www.cnblogs.com/_programmer/p/1570326.html