数据结构之线性表
线性结构是最常用、最简单的一种数据结构。而线性表是一种典型的线性结构。其基本特点是线性表中的数据元素是有序且是有限的。在这种结构中:
(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(“线性表溢出!\n”); 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为空!\n”); return ERROR; }
else if ( i<1||i>L->length )
{ printf(“要删除的数据元素不存在!\n”) ; 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)缺点:
插入和删除操作需要移动大量的元素。
当线性表长度变化较大时,难以确定存储空间的容量。
造成存储空间的“碎片”。