线性表是线性结构,我们来研究它的逻辑关系,用ADT(抽象数据类型)来表示,ADT的描述可以从顺序结构表示链式结构表示

线性表的表示与实现-------顺序结构

 

关于顺序结构

  顺序结构用顺序表来实现和描述。顺序表在C语言中通常会用一维数组来表示顺序存储结构

 顺序表结构特点:随机查找,删除插入麻烦,可变大小。

    用一组地址连续的存储单元依次存放线性表中的数据元素,顺序表中的每个在逻辑上相邻的元素在物理存储位置上也是相邻的。如下图所示,a1,a2在逻辑上相邻,在物理表中的存储位置也是相邻的。

线性表【02】线性表的顺序表示与实现_插入删除

设每个元素占用C个存储单元 ,线性表中第i+1个元素的存储位置LOC(a i+1)和第i个元素存储位置之间的关系:  

            LOC(ai) = LOC(ai-1) + C

         一个数据元素所占存储量↑  

所有数据元素的存储位置均取决于第一个数据元素的存储位置

      LOC(ai) = LOC(a1) + (i-1)×C

                  ↑基地址

顺序映像的描述定义

  注意:在顺序结构中,由于顺序结构的特点(逻辑上相邻,物理上也相邻),在定义和实现顺序结构的时候,可以不使用指针,因为顺序结构每个元素的指向都是根据存储位置而固定好的,就是一个挨着一个。为了大家好理解,在顺序结构中,我们会用两种做法来描述顺序结构。一种是使用指针,一种是不使用指针。

  1. 不使用指针 
  2. #define  MAXSIZE     100  // 线性表存储空间的分配量,即数组长度 
  3. typedef  struct {     
  4.     ElemType   elem[MAXSIZE]; 定义数组 
  5.     int  length;   // 当前长度 ,线性表的元素个数,并不是数组长度 
  6. } SqList;  // 俗称 顺序表 
  7. 指针定义 
  8. #define  MAXSIZE     100  // 线性表存储空间的分配量,即数组长度 
  9. #define LISTINCREMENT    10 //线性表存储空间的分配增量 
  10. typedef  struct {     
  11.     ElemType   *elem;//存储空间基地址 
  12.   int  length;   // 当前长度 ,线性表的元素个数,并不是数组长度 
  13.   int  listsize;      //当前分配的存储容量 
  14. } SqList;  // 俗称 顺序表 

在上述代码中,用两种方法定义了一个结构体的顺序表,用ElemType表示未知数据类型的总称。

SqList为表的名称。

  注意:不使用指针的顺序定义是定义了一个长度不可变的空间,即空间的大小不能变,就是MAXSIZE(100)个元素。 而使用指针定义是定义了一个长度可变的空间,它是动态内存分配的一维数组,可以在原来分配空间大小的基础上再增加LISTINCREMENT(10)个空间大小。 

线性表的顺序实现(初始化、查找、插入、删除、取元素)

线性表有两种实现,一种是顺序实现,一种是链式实现。上述中我们已经定义了顺序表SqList,那么我们现在先用顺序实现。

顺序实现的几个例子:注意:在上述定义顺序表SqList时,我们用了两种方法(非指针和指针),那么在实现顺序结构时,也用两种方法进行实现,分别对应两种定义。

初始化: 将表中的元素进行初始化。 

  1. Status InitList_Sq( SqList& L )   
  2. {    // 构造一个空的线性表   
  3.     L.length = 0; //表长度为0,即元素个数设置为0  
  4.     return OK;  
  5. } // InitList_Sq  
  6. 指针实现  
  7. Status InitList_Sq( SqList& L )   
  8. {    // 构造一个空的线性表   
  9.     //用动态内存分配表的空间  
  10.   L.elem=(ElemType *)malloc(MAXSIZE *sizeof(ElemType));  
  11.   If(!L.elem)exit(OVERFLOW); //分配失败  
  12.   L.length = 0;  //表长度为0,即元素个数设置为0
  13.   L.listsize=MAXSIZE ;//初始存储容量,也就上定义中的10  
  14.     return OK;  
  15. } // InitList_Sq 

 

L.elem=(ElemType *)malloc(MAXSIZE *sizeof(ElemType)); malloc用于分配指定内存空间的库函数,它的作用就是分配空间,一个元素所占空间大小为sizeof(ElemType),一共有MAXSIZE个元素,所以一共分配的空间大小为MAXSIZE 乘以sizeof(ElemType),分配完成后将分配的空间转换为(ElemType*)类型的指针,然后赋给指针L.elem.

 

查找(定位):在顺序表中找到指定元素的位置,返回其下标。

线性表【02】线性表的顺序表示与实现_realloc_02

  1. int Locate (SqList L, ElemType x)  
  2.    // 在顺序表中查询第一个等于x的数据元素, 
  3.   // 若存在,则返回它的位序,否则返回 0 
  4.     i = 1;      // i 的初值为第 1 元素的位序 ,表示第几个元素
  5. //L.elem[i-1]为最后一个元素 ,L.elem[0]为第一个元素,[]内是下标
  6.     while( L.elem[i-1] !=x )  //从第一个元素开始,如果不等于要查找元素x,就再下一个,一直找到为止
  7.  ++i;    
  8.        if (i <= L.length)    return i; //找到元素位置i后,如果i在表中就返回i
  9.        else     return 0; 
  10. } // Locate 
  11. 指针实现 
  12. int Locate (SqList L, ElemType e,Status(*compare)(ElemType,ElemType))  
  13.    // 在顺序表中查询第一个等于x的数据元素, 
  14.   // 若存在,则返回它的位序,否则返回 0 
  15.   i = 1;      // i 的初值为第 1 元素的位序 
  16.   p=L.elem;  //将第一个元素的地址赋给指针p
  17.     while( i<=L.length && !(*compare)(*p++,e))//判断L中第1个与e 满足关系compare()的数据元素
  18. ++i; 
  19.        if (i <= L.length)    return i; 
  20.        else     return 0; 
  21. } // Locate 

 

while( i<=L.length && !(*compare)(*p++,e))中 compare是一个函数,*p++和e 都是这个函数的参数。这句代码理解为:先是p指针指向的值加1,得到的值和e变量作为实际参数传递给函数compare进行处理,然后根据compare函数处理完的结果进行真假判断(真为1,假为0),然后!取反。

插入: 在顺序表中指定位置插入一个已知元素

 

(a1, , ai-1, ai, , an) 改变为(a1, , ai-1, e, ai, , an)

 

 

线性表【02】线性表的顺序表示与实现_顺序实现_03

  1.  Status ListInsert(SqList &L, int i, ElemType e)  
  2. {    // 在顺序表L的第 i 个元素之前插入新的元素e, 
  3.     // i 的合法范围为  1≤i≤L.length+1 
  4.      if (i < 1 || i > L.length+1) return ERROR;  // 插入位置不合法 
  5.      for ( jL.length ; j>=i ; j - - )   //从后向前查找 
  6.         L.elem[j]=L.elem[j-1];  // 插入位置及之后的元素右移 
  7.         L.elem[i-1] = e ;       // 插入e 
  8.      ++L.length;   // 表长增1 
  9.      return OK; 
  10. } // ListInsert_Sq   
  11. 指针 
  12. Status ListInsert(SqList &L, int i, ElemType e)  
  13. {    // 在顺序表L的第 i 个元素之前插入新的元素e, 
  14.     // i 的合法范围为  1≤i≤L.length+1 
  15.      if (i < 1 || i > L.length+1) return ERROR;  // 插入位置不合法 
  16.      if(L.length>=L.listsize){ 
  17.         //先释放原来L.elem所指内存区域,重新分配空间同时将原有数据从头到尾拷贝到新分配的内存区域                            
  18.         newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));  
  19.        if(!newbase)exit(OVERFLOW); 
  20.        L.elem=newbase
  21.        L.listsize+=LISTINCREMENT
  22.      } 
  23.       q=&(L.elem[i-1]); 
  24.      for ( p=&(L.elem[L.length-1]);p>=q;--p) * (p+1)=*p ;   //插入位置及之后的元素右移 
  25.      *q=e
  26.      ++L.length;   // 表长增1 
  27.      return OK; 
  28. } // ListInsert_Sq   

 

 newbase=(ElemType*)realloc(L.elem,(L.listsize+MAXSIZE)*sizeof(ElemType));这句代码实际上是从新分配了一个空间,然后把原来空间复制到新空间,然后又增加了一个新的空间,这个新的空间大小为LISTINCREMENT.

删除:将表中指定位置的元素删除

 

(a1, , ai-1, ai, ai+1, , an) 改变为 (a1, , ai-1, ai+1, , an)

 

 

线性表【02】线性表的顺序表示与实现_顺序实现_04

  1. Status ListDelete (SqList &L, int i, ElemType &e)  
  2. {   // 在顺序表L中删除第i个元素,用e返回删除的值 
  3.     // i 的合法范围为  1≤i≤L.length+1 
  4.      if (i < 1 || i > L.length)   return ERROR;  // 插入位置不合法 
  5.      e=L.elem[i-1]; 将被删除的元素赋给e 
  6.      for(j=i+1;j<=length;j++) 
  7.          L.elem[j-2]=L.elem[j-1]; 
  8.      L.length--; 
  9.      return OK; 
  10. } // ListDelete_Sq 
  11. 指针 
  12. Status ListDelete (SqList &L, int i, ElemType &e)  
  13. {   // 在顺序表L中删除第i个元素,用e返回删除的值 
  14.     // i 的合法范围为  1≤i≤L.length+1 
  15.      if (i < 1 || i > L.length)   return ERROR;  // 插入位置不合法 
  16.      p=&(L.elem[i-1]); 
  17.      e=*p; 
  18.      q=L.elem+L.length-1; 
  19.      for(++p;p<=q;++p)*(p-1)=*p; 
  20.       --L.length; 
  21.      return OK; 
  22. } // ListDelete_Sq 

取元素

  1. Status GetElem (SqList L, int i, ElemType &e) { 
  2.      e=L.elem[i-1]; 
  3.      return OK; 
  4. }//GetElem 

notice:

 1. 在算法中经常会遇到“&”该不该加的问题,比如:

   在Status ListInsert(SqList &L, int i, ElemType e)中为什么L前面加了&,而e没有。

&是引用,是一个传递参数的问题。X如果在此函数中有值的变化,那么X前面就应该加上&----&X, 比如:在插入中,表的长度加了1,表L有变化,所有&L,在删除中,元素被删除了,e从有值到没值,发生了变化,所以在删除中是&e.

 

2.   注意位序和下标。在一个表中第i(位序)个元素的值是L.elem[i-1](下标),位序是1,2,3,4,。。N    下标是        从0开始的。

3.  表长为元素的个数:L.length 

    第一个元素为L.elem[0](第一个元素),最后一个元素为L.elem[length-1]   

 

关于线性表的顺序结构实现,我们就一起学习以上的几种操作,下一篇文章一起学习线性表中的链式实现。