数据结构之线性表

线性结构是最常用、最简单的一种数据结构。而线性表是一种典型的线性结构。其基本特点是线性表中的数据元素是有序且是有限的。在这种结构中:

(1) 存在一个唯一的被称为“第一个”的数据元素;

(2)存在一个唯一的被称为“最后一个”的数据元素;

(3)除第一个元素外,每个元素均有唯一一个直接前驱;

(4)除最后一个元素外,每个元素均有唯一一个直接后继。

一、线性表的定义

  线性表:是由n(n≧0)个数据元素(结点)a1,a2, …an组成的有限序列。该序列中的所有结点具有相同的数据类型。其中数据元素的

个数n称为线性表的长度。

  当n=0时,称为空表。

  当n>0时,将非空的线性表记作: (a1,a2,…an) a1称为线性表的第一个(首)结点,an称为线性表的最后一个(尾)结点。

  a1,a2,…ai-1都是ai(2≦i≦n)的前驱,其中ai-1是ai的直接前驱; ai+1,ai+2,…an都是ai(1≦i ≦n-1)的后继,其中ai+1是ai的直接后继。

二、线性表的抽象数据类型

ADT List{

    数据对象:D = { ai | ai∈ElemSet, i=1,2,…,n, n≧0 }

    数据关系:R = {<ai-1, ai> | ai-1, ai∈D, i=2,3,…,n }

    基本操作:

      InitList( &L )

        操作结果:构造一个空的线性表L;

      ListLength( L )

        初始条件:线性表L已存在;

        操作结果:若L为空表,则返回TRUE,否则返回FALSE;

      ….

      GetElem( L, i, &e )

        初始条件:线性表L已存在,1≦i≦ListLength(L);

        操作结果:用e返回L中第i个数据元素的值;

      ListInsert ( L, i, &e )

        初始条件:线性表L已存在,1≦i≦ListLength(L) ;

        操作结果:在线性表L中的第i个位置插入元素e;

       …

} ADT List

三、线性表的顺序存储结构

(1)顺序存储的定义:

  把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。用这种方法存储的线性表简称顺序表。

(2)顺序存储的特点:

  线性表的逻辑顺序与物理顺序一致;

  数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现。

(3)顺序存储方式:

  我们用结构类型来定义顺序表类型。

   #define OK 1

  #define ERROR -1

  #define MAX_SIZE 100

  typedef int Status ;

  typedef int ElemType ;

  typedef struct sqlist

    {   ElemType Elem_array[MAX_SIZE] ;

        int length ;

     } SqList ;

(4)地址计算方法:

  设线性表的每个元素需占用l个存储单元,以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中第i+1个数据元素的存储位置

LOC(ai+1)和第i个数据元素的存储位置LOC(ai)之间满足下列关系:

  LOC(ai+1)=LOC(ai)+l

  线性表的第i个数据元素ai的存储位置为:

   LOC(ai)=LOC(a1)+(i-1)*l

四、顺序存储结构的插入与删除

(1)顺序表的初始化:

Status Init_SqList( SqList *L )

  {  L->elem_array=( ElemType * )malloc(MAX_SIZE*sizeof( ElemType ) ) ;

     if ( !L -> elem_array ) return ERROR ;

    else { L->length= 0 ; return OK ; }

  }

(2)顺序表的插入操作:

插入操作的实现步骤:

  将线性表L中的第i个至第n个结点后移一个位置。

  将结点e插入到结点ai-1之后。

   线性表长度加1。

算法描述:

Status Insert_SqList(Sqlist *L,int i ,ElemType e)

  {  int j ; if ( i<0||i>L->length-1) return ERROR ;

     if (L->length>=MAX_SIZE)

    { printf(“线性表溢出! ”); return ERROR ; }

    for ( j=L->length–1; j>=i-1; --j )

    L->Elem_array[j+1]=L->Elem_array[j];

    /* i-1位置以后的所有结点后移 */

    L->Elem_array[i-1]=e;

    /* 在i-1位置插入结点 */

    L->length++ ;

    return OK ;

   }

(3)顺序表的删除操作

删除操作的实现步骤:

  将线性表L中的第i+1个至第n个结点依此向前移动一个位置。

  线性表长度减1。

算法描述:

ElemType Delete_SqList(Sqlist *L,int i)

  {   int k ; ElemType x ;

    if (L->length==0)

    { printf(“线性表L为空! ”); return ERROR; }

    else if ( i<1||i>L->length )

    { printf(“要删除的数据元素不存在! ”) ; return ERROR ; }

    else { x=L->Elem_array[i-1] ; /*保存结点的值*/

    for ( k=i ; k<L->length ; k++)

      L->Elem_array[k-1]=L->Elem_array[k]; /* i位置以后的所有结点前移 */

    L->length--; return (x);

    }

  }

(4)插入和删除操作的时间复杂度:

  由于元素插入到第i个位置,或者删除第i个元素,需要移动第n-i个元素。根据概率原理,每个位置插入或者删除元素的可能性是相同的,也就是说位置靠前,

移动元素多,位置靠后,移动元素少。最终平均移动次数和最中间的那个元素的移动次数相等,为(n-1)/2。因此,可以得出,平均时间复杂度还是O(n)。

五、线性表顺序存储结构的优缺点

(1)优点:

  无须为表示表中元素之间的逻辑关系而增加额外的存储空间。

  可以快速的存取表中任意位置的元素。

(2)缺点:

  插入和删除操作需要移动大量的元素。

  当线性表长度变化较大时,难以确定存储空间的容量。

  造成存储空间的“碎片”。

原文地址:https://www.cnblogs.com/junjiang3/p/7822059.html