线性结构的特点
- 存在唯一一个被称为“第一个”的数据元素。
- 存在唯一一个被称为“最后一个”的数据元素。
- 除第一个外,集合中的每一个数据元素只有一个前驱。
- 除最后一个外,集合中的每一个数据元素只有一个后继。
线性表的类型定义
线性表中的元素个数n(n ≥ 0)定义为线性表地长度,n = 0时称为空表。
在非空表中的每一个数据元素都有一个确定的位置。
在稍复杂的线性表中,一个数据元素可以由若干个数据项组成,在这种情况下,常把数据元素称为记录,含有大量记录的线性表称为文件。
抽象数据类型线性表
ADT List{
数据对象:D = {ai|ai∈ElemSet,i = 1,2,……,n,n ≥ 0}
数据关系:Rl = {<ai-1,ai>|ai-1,ai∈D,i = 2,……,n}
基本操作:
InitList(&L)
DestroyList(&L)
ClearList(&L)
ListEmpty(L)
ListLength(L)
GetElem(L,i,&e)
LocateElem(L,e,compare())
PriorElem(L,cur_e,&pre_e)
NextElem(L,cur_e,&next_e)
ListInsert(&L,i,e)
ListDelete(&L,i,&e)
ListTraverse(L,visit())
Locate(L,x)
}ADT List
线性表的顺序表示和实现
线性表的顺序性表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
假设线性表的每个元素需占用l个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。
一般来说,线性表的第i个数据元素ai的存储位置为
LOC(ai) = LOC(a1) + (i - 1) * l
式中LOC(a1)是线性表中的第一个数据元素ai的存储位置,通常称作线性表的起始位置或基地址。
线性表的这类机内表示称作线性表的顺序存储结构或顺序映像。
//---线性表的动态分布顺序存储结构---
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{
ElemType *elem; //存储空间的基址
int length; //当前长度
int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位)
}SqList;
InitList(&L)
操作结果:构造一个空的线性表L。
Status InitList_Sq(SqList &L){
//构造一个空的线性表L。
L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if(!L.elem)
exit(OVERLOW); //存储分配失败
L.length = 0; //空表的长度为0
L.listsize = LIST_INIT_SIZE; //初始存储容量
return OK;
}//InitList_Sq
Status1
L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));2
DestroyList(&L)
初始条件:线性表L已存在。
操作结果:销毁线性表L。
ClearList(&L)
初始条件:线性表L已存在。
操作结果:将L重置为空表。
ListEmpty(L)
初始条件:线性表L已存在。
操作结果:若L为空表,则返回TURE,否则返回FALSE。
ListLength(L)
初始条件:线性表L已存在。
操作结果:返回L中数据元素个数。
GetElem(L,i,&e)
初始条件:线性表L已存在,i ≤ i ≤ListLength(L)。
操作结果:用e返回L中第i个数据元素的值。
LocateElem(L,e,compare())
初始条件:线性表L已存在,compare()是数据元素判定函数。
操作结果:返回L中第一个与e满足关系compare()的数据元素的位序。若这样的数据元素不存在,则返回值为0。
int LocateElem_Sq(SqList L,ElemType e,Statue(*compare)(ElemType,ElemType)){
i = 1;
p = L.elem;
while(i <= L.length && !(*compare)(*p++, e))
++i;
if(i <= L.length)
return i;
else
return 0;
}
PriorElem(L,cur_e,&pre_e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。
NextElem(L,cur-e,&next-e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义。
ListInsert(&L,i,e)
初始条件:线性表L已存在,i ≤ i ≤ ListLength(L) + 1。
操作结果:在L的第i个位置之前插入新的数据元素e,L的长度加1。
Status ListInsert_Sq(SqList &L, int i, ElemType e){
//在顺序线性表L中的第i个位置之前插入新的元素e,
//i的合法值为i ≤ i ≤ ListLength_Sq(L) + 1
if(i < 1 || i > L.length + 1)
return ERROR; //i值不合法
if(L.length >= L.listsize){ //当前存储空间已满,增加分配
newbase = (ElemType *)realloc(L.elem,(L.listsize + LISTINCREMENT) * sizeof(Elempy));
if(!newbase)
exit(OVERFLOW); //存储分配失败
L.elem = newbase; //新基址
L.listsize += LISTINCREMENT;//增加存储容量
}
q = &(L.elem[i - 1]); //q为插入位置
for(p = &(L.elem[L.length - 1]); p>= q; --p)
*(p + 1) = *p; //插入位置及之后的元素右移
*q = e; //插入e
++L.length; //表长增1
return OK;
}
newbase = (ElemType *)realloc(L.elem,(L.listsize + LISTINCREMENT) * sizeof(Elempy));3
q = &(L.elem[i - 1]);4
ListDelete(&L,i,&e)
初始条件:线性表L已存在且非空,i ≤ i ≤ListLength(L)。
操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1。
Status ListDelete_Sq(SqList &L, int i, ElemType &e){
//
//
if((i < 1) || (i > L.length)) //i值不合法
return ERROR;
p = &(L.elem[i - 1]); //p为被删除元素的位置
e = *p; //被删除元素的值赋给e
q = L.elem + L.length - 1; //表尾元素的位置
for(++p; p <= q; ++p)
*(p - 1) = *p; //被删除元素之后的元素左移
--L.length; //表长减1
return OK;
}//ListDelete.Sq
ListTraverse(L,visit())
初始条件:线性表L已存在。
操作结果:依次对L的每个数据元素调用函数visit()。一旦visit()失败,则操作失败。
Locate(L,x)
初始条件:线性表L已存在。
操作结果:返回L中第一个与x相等的数据元素的位序。若这样的数据元素不存在,则返回一个“空序号”,如-1。
int Locate(SeqList L, ElemType x){
int i =1;
while((i <= L.length) && (L.elem[i] != x))
++i;
if(i <= L.length)
return i;
else
return -1;
}
顺序表的归并算法
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){
//已知顺序线性表La和Lb的元素按值非递减排列
//归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列
pa = La.elem;
pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
pc = Lc.elem = (ElemType*)malloc(Lc.listsize * sizeof(ElemType));
if(!Lc.elem)
exit(OVERFLOW);
pa_last = La.elem + La.length - 1;
pb_last = Lb.elem + Lb.length - 1;
while(pa <= pa_last && pb <= pb.last){
if(*pa <= *pb)
*pc++ = *pa++;
else
*pc++ = *pb++;
}
while(pa <= pa.last)
*pc++ = *pa++;
while(pb <= pb.last)
*pc++ = *pb++;
}
该算法的时间复杂度为O(La.length + Lb.length)
c语言中没有status这个关键字。但一般写程序时,会定义这样的一个类型,用来表示成功或失败状态。 ↩︎
malloc() 函数用来动态地分配内存空间,其原型为:void* malloc (size_t size);
函数的返回值类型是 void *,void 并不是说没有返回值或者返回空指针,而是返回的指针类型未知。所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型。 ↩︎1.如果当前内存段后有足够的空间,realloc()返回原来的指针。
2.如果当前内存段后没有足够的空间,realloc()返回一个新的内存段的指针。 ↩︎C语言中数组的下标从“0”开始,因此,若L是SqList类型的顺序表,则表中第i个数据元素是L.elem[i - 1]。 ↩︎