• 数据结构 第4章 数组和广义表


    4 数组和广义表


    本章主要介绍下列内容:
      1.数组的定义、基本运算和存储结构
      2.特殊矩阵的压缩存储
      3.广义表的定义、术语、存储结构、运算
      4.递归算法设计
    课时分配:
        1
    两个学时,2两个学时,3两个学时, 4两个学时
    重点、难点:
       
    特殊矩阵的压缩存储、广义表的存储结构、递归算法设计

     

    第一节 数组

    1.数组的定义和基本运算
       
    数组的特点是每个数据元素可以又是一个线性表结构。因此,数组结构可以简单地定义为:若线性表中的数据元素为非结构的简单元素,则称为一维数组,即为向量;若一维数组中的数据元素又是一维数组结构,则称为二维数组;依次类推,若二维数组中的元素又是一个一维数组结构,则称作三维数组。
       
    结论:线性表结构是数组结构的一个特例,而数组结构又是线性表结构的扩展。举例:

        其中,A是数组结构的名称,整个数组元素可以看成是由m个行向量和n个列向量组成,其元素总数为m×n C语言中,二维数组中的数据元素可以表示成a[表达式1][表达式2],表达式1和表达式2被称为下标表达式,比如,a[i][j] 数组结构在创建时就确定了组成该结构的行向量数目和列向量数目,因此,在数组结构中不存在插入、删除元素的操作。
       
    二维数组结构的基本操作:
    1)给定一组下标,修改该位置元素的内容 Assign(A,elem,index1,index2)
    2)给定一组下标,返回该位置的元素内容 Value(A,elem,index1,index2)
    2
    .数组的存储结构
       
    从理论上讲,数组结构也可以使用两种存储结构,即顺序存储结构和链式存储结构。然而,由于数组结构没有插入、删除元素的操作,所以使用顺序存储结构更为适宜。换句话说,一般的数组结构不使用链式存储结构。 组成数组结构的元素可以是多维的,但存储数据元素的内存单元地址是一维的,因此,在存储数组结构之前,需要解决将多维关系映射到一维关系的问题。举例:      LOC(i,j)=LOC(0,0)+(n*i+j)*L
       
    数组结构的定义:
           #define MAX_ROW_INDEX 10
           #define MAX_COL_INDEX 10
           typedef struct{Elemtype elem[MAX_ROW_INDEX][MAX_COL_INDEX]        } ARRAY;
       
    基本操作算法举例:
    1)给数组元素赋值
        void Assign(ARRAY *A,Elemtype elem,int index1,int index2)
        { if (index1<0||index1>=MAX_ROW_INDEX||index2<0||index2>=MAX_COL_INDEX)      exit(ERROR);
        else A->elem[index1][index2]=elem; }
    2)返回给定位置的元素内容
        int Value(ARRAY A,Elemtype *elem,int index1,int index2)
        { if (index1<0||index1>=MAX_ROW_INDEX|| index2<0||index2>=MAX_COL_INDEX) return FALSE;
        else { *elem= A.elem[index1][index2]; return OK;   
    3
    .矩阵的压缩存储
       
    矩阵是在很多科学与工程计算中遇到的数学模型。在数学上,矩阵是这样定义的:它是一个由s×n个元素排成的s行(横向)n列(纵向)的表。下面就是一个矩阵

    31特殊矩阵


       
    对于这些特殊矩阵,应该充分利用元素值的分布规律,将其进行压缩存储。选择压缩存储的方法应遵循两条原则:一是尽可能地压缩数据量,二是压缩后仍然可以比较容易地进行各项基本操作。
       
    三种特殊矩阵的压缩方法:
     
    1)对称矩阵 对称矩阵的特点是aij=aji。一个n×n的方阵,共有n2个元素,而实际上在对称矩阵中有n(n-1)/2个元素可以通过其他元素获得。压缩的方法是首先将二维关系映射成一维关系,并只存储其中必要的n(n+1)/2个(主对角线和下三角)元素内容,这些元素的存储顺序以行为主序。举例: 假设定义一个数组型变量:int A[10];

        k是对称矩阵位于(ij)位置的元素在一维数组中的存放位置。 操作算法的实现:
        int Value(int A[],Elemtype *elem,int i,int j) {
        if(i<1||i>MAX_ROW_INDEX|| j<1||j>MAX_COL_INDEX) return FALSE;
        else { if (i>=j) k=i*(i-1)/2+j-1;
               else k=j*(j-1)/2+i-1;
               *elem=A[k];
               return TRUE; }
              }
      
    2)下(上)三角矩阵 下三角矩阵的压缩存储与上面讲述的对称矩阵的压缩存储一样,只是将上三角部分的常量值存储在0单元,下三角和主对角上的元素从1号单元开始存放。 举例:

        操作算法的实现:
          int Value(int A[],Elemtype *elem,int i,int j)
          {
          if(i<1||i>MAX_ROW_INDEX||j<1||j>MAX_COL_INDEX) return FALSE;
          else { if (i>=j) k=i*(i-1)/2+j;
                 else k=0;
                 *elem=A[k];
                 return TRUE;
                }
          }
      
    3)对角矩阵
       
    我们以三阶对角矩阵为例讨论一下它的压缩存储方法。对于对角矩阵,压缩存储的主要思路是只存储非零元素。这些非零元素按以行为主序的顺序,从下标为1 的位置开始依次存放在一维数组中,而0位置存放数值0

        操作算法的实现:
          int Value(int A[ ],Elemtype *elem,int i,int j)
          {
          if(i<1||i>MAX_ROW_INDEX||j<1||j>MAX_COL_INDEX) return FALSE;
          else { if (j>=(i-1)&&j<=(i+1)) k=3*(i-1)+j-i+1;
                 else k=0;
                 *elem=A[k];
                 return TRUE;
                }
          }
    3
    2 稀疏矩阵的压缩存储

       
    类型定义:
          #define MAX_SIZE 100
    最大的非零元素个数
          typedef struct{
          int i,j; //
    行序号、列序号
          Elemtype value; //
    非零元素值
          }Three_Elem;
          typedef struct {
          Three_Elem Elem[MAXSIZE]; //
    存储非零元素的一维数组
          int rows,cols,tu; //
    稀疏矩阵的总行数、列数及非零元素个数
          }Matrix;
       
    操作算法的实现:
      
    1)返回元素内容
          int Value(Matrix M,Elemtype *elem,int i,int j)
          if (i<1||i>rows||j<1||j>cols) exit(ERROR);
          else { for (p=0;p<M.tu;p++)
                   if(M.elem[p].i==i&&M.elem[p].j==j)
                   { *elem=M.elem[p].value; return OK; }
       else if (M.elem[p].i>i||M.elem[p].i==i&&M.Elem[p].j>j) break;
          *elem=0;
          return OK;
              }
            }
      
    2)输出三元组表示的稀疏矩阵
          void Print(Matrix M)
          {
          for (p=0,i=1;i<=M.rows;i++) {
          for (j=1;j<=M.cols;j++)
    if(p<M.tu&&M.elem[p].i==i&&M.elem[p].j==j) printf("%4d",M.elem[p++].value;);
    else printf("%4d",0);
          printf("\n");
          }
         }

    第二节 广义表

    1. 广义表的定义
       
    广义表(Lists,又称列表)是线性表的推广。在第2章中,我们把线性表定义为n>=0个元素a1,a2,a3,…,an的有限序列。线性表的元素仅限于原子项,原子是作为结构上不可分割的成分,它可以是一个数或一个结构,若放松对表元素的这种限制,容许它们具有其自身结构,这样就产生了广义表的概念。
       
    广义表是n(n>=0)个元素a1,a2,a3,…,an的有限序列,其中ai或者是原子项,或者是一个广义表。通常记作LS=a1,a2,a3,…,an)LS是广义表的名字,n为它的长度。若ai是广义表,则称它为LS的子表。
       
    通常用圆括号将广义表括起来,用逗号分隔其中的元素。为了区别原子和广义表,书写时用大写字母表示广义表,用小写字母表示原子。若广义表LSn>=1)非空,则a1LS的表头,其余元素组成的表(a1,a2,…an)称为LS的表尾。
       
    显然广义表是递归定义的,这是因为在定义广义表时又用到了广义表的概念。广义表的例子如下:
    1A=()--A是一个空表,其长度为零。
    2B=e--B只有一个原子eB的长度为1
    3C=a,(b,c,d))--C的长度为2,两个元素分别为原子a和子表(b,c,d)
    4D=ABC--D的长度为3,三个元素都是广义表。显然,将子表的值代入后,则有D=(( ),(e),(a,(b,c,d)))
    5E=E--这是一个递归的表,它的长度为2
          E
    相当于一个无限的广义表E=(a,(a,(a,(a,…)))).
       
    从上述定义和例子可推出广义表的三个重要结论:
    1)广义表的元素可以是子表,而子表的元素还可以是子表。由此,广义表是一个多层次的结构,可以用图形象地表示。
    2)广义表可为其它表所共享。例如在上述例(4)中,广义表ABCD的子表,则在D中可以不必列出子表的值,而是通过子表的名称来引用。
    3)广义表的递归性。
       
    综上所述,广义表不仅是线性表的推广,也是树的推广。
    2.
    广义表的存储结构

       
    由于广义表(a1,a2,a3,…an)中的数据元素可以具有不同的结构,(或是原子,或是广义表),因此,难以用顺序存储结构表示,通常采用链式存储结构,每
    个数据元素可用一个结点表示。
       
    由于广义表中有两种数据元素,原子或广义表,因此,需要两种结构的结点:一种是表结点,一种是原子结点。 下面介绍两种广义表的链式存储结构。
       
    表结点由三个域组成:标志域、指示表头的指针域和指示表尾的指针域;而原子域只需两个域:标志域和值域。

        其类型定义如下:
            typedef enum{ATOM,LIST}elemtag;
            typedef struct glnode{
            elemtag tag;
            union{
            atomtype atom;
            struct {
            struct glnode *hp,*tp;
            }ptr;
            };
            } *glist;
       
    例见书。
    3.
    分析求广义表深度和长度的递归算法(见教材)
       
    这部分内容比较难,用1个课时讲解,用1个课时答疑

    image

    欢迎访问我的专业知识博客!
    博主:白途思(begtostudy)
    微信/QQ:370566617
    Email:begtostudy#gmail.com
    欢迎访问我的其他博客:我的编程知识博客 我的学术知识博客

  • 相关阅读:
    FFmpeg 协议初步学习
    HTML DOM(一):认识DOM
    ant 安装
    ubunut 查看port被哪个程序占用
    cacti气象图调整(批量位置调整、更改生成图大小等)
    内网port映射具体解释(花生壳)
    HDU 2647 Reward(图论-拓扑排序)
    白话经典算法系列之七 堆与堆排序
    Codeforces Round #191 (Div. 2)---A. Flipping Game
    Serverlet具体解释
  • 原文地址:https://www.cnblogs.com/begtostudy/p/1831957.html
Copyright © 2020-2023  润新知