线性结构的特点:在数据元素的非空有限集合中(1)存在唯一的一个被称作“第一个”的数据元素,(2)存在唯一的一个被称作“最后一个”的数据元素,(3)除第一个外,集合中的每一个数据元素均只有一个前驱,(4)除最后一个数据元素外,每一个元素均只有一个后继。
一个线性表是n个数据元素的有限序列。线性表的数据元素个数n(n>=0)定义为线性表的长度,n=0时称为空表。对一个线性表不仅可以进行访问,还可以进行插入和删除的操作。
例题2-1:假设利用两个线性表LA和LB分别表示两个集合A和B,现在要求一个新的集合A=A U B。
分析:此时在这个题目里面有如下的操作:(1)扩大线性表LA(2)将存于LB而不存于LA中的数据元素插入到LA中
void union(SqList &LA,SqList LB){//将所有不在LA中但是存在于LB中的数据元素插入到LA中
Int LA_len = ListLength(LA);
Int LB_len = ListLength(LB);
for(int i = 0;iif(!LocateElem(LA,e,equal))///LA中不存在和e相同的数据元素
ListInsert(LA,++LA_len,e) // 插入
}
例题2-2:已知线性表LA和LB中的元素按照值非递减的有序排列,现要求合并LA和LB为LC然后将各个数据元素任然按值非递减有序排列。
分析:只要先设一个新的线性表LC为新表,然后依次将LA和LB的元素存入LC即可,所以可以设两个指针i和j分别指向LA和LB中的某个元素,若i所指的元素为a,j所指的元素为b,那么当a>b时,c的取值为b,当a<=b时,c的取值是a;显然指针i和j的初始值都是1,在所指元素插入到LC中以后,在LA或者LB中顺序后移。
Status Mergelist(SqList LA,SqList LB,SqList &LC){//已知线性表LA和LB中的元素按照值非递减排列,LC也按照非递减排列
InitLIst(LC);
int i= j=1;k=0;
ElemType LA_len=ListLength(lA);
ElemType LB_len=ListLength(LB);
while((i<=LA_len)&&(j<=LB_len)) {//LA 和 LB均为非空
GetElem(lA,i,ai);
GetElem(LB,j,bj);
if(ai<=bj){
ListIntert(LC,++k,ai);
++i;
}else{
ListInsert(LC,++k,bj);
++j;
}
}
while(i<=LA_len){
GetElem(LA,i++,ai);
ListInsert(LC,++K,ai);
}
while(j<=LB_len){
GetElem(LB,j++,bj);
ListInsert(LC,++K,bj);
}
}
对于顺序表的合并,上述的算法的基本操作是“元素赋值”,时间复杂度为O(LA.length+LB.length),该算法还可以改写成如下的算法:
void MergeList(SqList LA,SqList LB,SqList &LC){
ElemType *pa,*pb,*pc,*pa_last,*pb_last;
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++;// 插入LA的剩余元素
while(pb <= Pb_last)*pc++ = *pb++;// 插入LB的剩余元素
}
该算法具有线性的时间复杂度,原因是(1):由于LA和LB中的数据元素值是递增的(同一集合中元素不等),则对LB中的每个元素,不需要在LA中从表头到表尾进行全程搜索;(2)由于用新表LC表示并集,则插入实际的操作时通过复制来进行的。其时间复杂度是O(nlogn)。
附录:ADT LIST的各个算法的实现:
ADT List{
基本操作:
InitList(&L)//构造一个空表
DestroyList(&L)//销毁线性表L
ClearList(&L)//将L重置为一个空表
ListEmpty(L)//若L为空表,则返回TRUE,否则返回FALSE
ListLength(L)//返回表L的长度(即为L的数据元素个数)
GetElem(L,i,&e)//用e返回L中第i个元素的值
LocateElem(L,e,compare())//返回L中第一个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,返回值为0
PriorElem(L,cur_e,&pre_e)//若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无意义
NextElem(L,cur_e,&next_e)//若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无意义
ListInsert(&L,i,e)//在线性表L的第i个位置上插入新的数据元素e,L的长度加1
ListDelete(&L,i,&e)//删除L的第i个数据元素,并用e返回其值,L的长度减1
ListTraverse(L,visit())//依次对L的每个数据元素调用visit(),一旦visit()失败,则操作失败
}ADT List
InitList(&L):
Status InitList(SqList& L){//构造一个空的线性表
L.elem=(ElemType *)malloc(MAX_SIZE*sizeof(ELemType));//申请内存空间
if(!L.elem) return ERROR;
else{
L.length = 0;
L.listsize= MAX_SIZE;
return OK;
}
}
DestroyList(&L):
void DestroyList(SqList &L){//销毁L
if(L.elem)
free(L.elem);//释放线性表占据的所有存储空间
}
ClearList(&L):
void ClearList(Sqlist &L){//清空L
L.length=0;//将线性表的长度置为0
}
ListEmpty(L):
Status ListEmpty(SqList L){
if(L.length==0)return TRUE;
else return FALSE;
}
ListLength(L):
Status ListLength(L){
return L.length;
}
GetElem(L,i,&e):
Stutas GetElem(SqList L,int i,ElemType e){//初始条件:顺序线性表L已存在,1≤i≤ListLength(L)用e返回L中第i个数据元素的值,注意i指位置,第1个位置的数组是从0开始
if(L.length==0||i<0||i>L.length) return ERROR;
else{
*e = L.elem[i-1];
return OK;
}
}
LocateElem(L,e,compare()):
Status LocateElem(SqList L,ElemType e,Status(*compare)(int a,int b)){//返回L中第一个大于e的数据元素的位序 实现一
for(i=0;i<=L.length-1;i++){
if(compare(L.elem[i],e)==Ok) {
return i;
break;
}else{
continue;
}
}
if(i==L.length-1&&(*compare)(L.elem[L.length-1],e)==FALSE)
return 0;
}
int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType)){
int i=1;
ElemType *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):
Status PriorElem(SqList L,ElemType cur_e,ElemType *pre_e){//实现一
int i=2;
ElemType *p = L.elem+1;//将p初始为L的第二个元素
while(i<=L.length&&*p!=cur_e){//从第二个元素开始,挨个与cur_e比较,直到相等或L的最后
p++;
i++;
}
if(i>L.length) return ERROR;
else {
*pre_e = *--p;//将p的前一个元素赋值给pre_e
return OK;
}
}
Status PriorElem(SqList L, ElemType cur_e, ElemType *pre_e) //实现二
{
int i;
int *p = L.elem;
for (i=0; ilength; i++,p++){//顺序表长度已知,故用for循环
if (i==0 && *p==cur_e) return ERROR;//此为第一个前驱
if (*p == cur_e){ //找到了当前元素且不是第一个元素,
*pre_e = *--p; //将其前驱赋给引用参数
return OK;
}
}
}
NextElem(L,cur_e,&next_e):
Status NextElem(SqList L,ElemType cur_e,ElemType *next_e){//实现一
int i=1;
ElemType *p = L.elem;
while(ilength&&*p!=cur_e){
p++;
i--;
}
if(i==L.length) return ERROR;
else{
*next_e=*++p;
return OK;
}
}
Status NextElem(sqlist L, int cur_e, int *nex_e){//最后一个元素无后继
int i;
int *p = L.elem;
for (i=0; ilength; i++) {//顺序表长度已知,故用for
if (i==L.length-1 || *p==cur_e) return ERROR;//当前元素为最后一个元素,无后继
if (*p == cur_e){
*nex_e = *++p; //将后继赋给引用参数带回
return OK;
}
}
}
ListInsert(&L,i,e):
Status ListInsert(SqList &L,int i,ElemType e){//在线性表L的第i个位置之前插入新的元素e,i的合法值为1<=i<=ListLength(L)+1;
if(i<0||i>L.ListLength+1) return ERROR;//i值不合法
else{
if(L.length>=L.listsize){//当前存贮空间已经满了,增加分配
ElemType *newbase = (ElemType*)realloc(L.elem,L.length+LISTINCREMENT)*sizeof(ElemType));
if(!newbase) return ERROR;
else{
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;
}
}
ListDelete(&L,i,&e):
Status ListDelete(SqList &L,int i,ElemType &e){//在顺序线性表L中删除第i个元素,并用e返回其值 ,i的合法值是1<=i<=ListLength(L);
if(i<1||i>L.length) return ERROR;
else{
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;
}
}
ListTraverse(L,visit()):
Status TravelList(SqList L,void(*visit)(SqList*)){
ElemType *p = L.elem;
int i = 1;
while(i
return OK;
}
上述代码里面提到的compare():
Stauts compare(int a,int b){
if(a>b) return OK;
else ERROR;
}
visit()只是个遍历的伪代码随你自己操作而定义。比如你定义个void visit(ElemType *L){printf(“%d”, L.elem[i]) ;} 输出该位置线性表的数据元素